-   文件IO 文件IO-  目的 -  将数据写入文件中 
 
-  
-  与标准IO的区别 (为什么要学习文件IO) -  标准IO只能操作普通文件和特殊的管道文件 
-  文件IO能操作几乎所有的的文件 
-  缓存区的目的 -  标准IO有缓存区 
-  文件IO没有缓存区 
-  根据右图描述 -  标准IO = 文件IO + buffer缓存区 
-  有缓存区的标准IO运行效率更高 
-  没有缓存区的的文件IO实时性更高 
 
-  
 
-  
-  系统调用 -  系统提供给用户的,让用户能够使用底层函数的接口。 
-  因为用户并不能直接调用这些个底层函数,必须通过所谓的"系统调用"这些函数才能调用到底层的函数 
-  既然printf最终调用write,为什么我们只把write称为系统调,不直接把printf称为系统调用呢? -  printf在不同的系统中,调用的函数是不一样的 -  在unix系统中,printf调用的就是write 
-  在windows,调用的就是XXXwrite函数了 
 
-  
 
-  
 
-  
-  来源不同 -  标准IO -  来自c语言的标准库,可以移植到任何支持c语言的系统环境中 
 
-  
-  文件IO -  来自UNIX内核提供的库函数 
 
-  
 
-  
-  句柄不同 -  标准IO -  使用的是FILE *流指针来描述文件 
 
-  
-  文件IO -  使用的是int类型,我们称为文件描述符,来描述文件 -  注意:int类型的文件描述符才是真正描述文件地址的一个变量 
 
-  
-  问题:明明是int类型,怎么去描述文件地址 -  stdin,stdout,stderr -  三个流文件(默认文件) 
 
-  
-  void* filearr[n] = {&stdin,&stdout,&stderr} -  filearr这个文件指针数组中,默认的存放了3个文件的地址,终端输入文件地址,终端输出文件地址,终端错误文件地址 
-  “标准输入流文件”的地址,被存放在数组中的第0个下标上 
-  “标准输出流文件”的地址,被存放在数组中的第1个下标上 
-  “标准错误流文件”的地址,被存放在数组中的第2个下标上 
-  所以,我们只要给"系统调用"提供下标信息,系统调用函数就会根据下标信息找到对应的文件指针 
 
-  
-  所以我们把文件在数组中的int类型的下标信息,称为这个文件的描述符 
 
-  
 
-  
 
-  
 
-  
-  如果获得int类型的描述符 -  open函数 -  int open(const char *pathname, int flags, mode_t mode) 
-  功能描述 -  打开pathname文件,如何打开由flags决定 (比如创建,清空,可读可写等属性)。 如果文件需要创建的话,创建权限值由mode决定 
 
-  
-  参数1 -  指定被打开的文件的路径名 
 
-  
-  参数2 -  打开时文件的属性 -  O_RDONLY -  文件以只读的形式打开 
 
-  
-  O_WRONLY -  文件以只写的形式打开 
 
-  
-  O_RDWR -  文件以读写的形式打开 
 
-  
-  O_APPEND -  文件以追加的形式打开 
 
-  
-  O_CREAT -  如果文件不存在,则创建文件打开 
 
-  
-  O_EXCL -  若文件存在则打开失败,配合O_CREAT使用 
-  实现效果:若文件不存在则创建文件, 如果存在则什么都不发生 
 
-  
-  O_NONBLOCK -  以非阻塞的形式打开文件 
 
-  
-  O_TRUNC -  若文件存在则清空文件打开 
-  即fopen的第二个参数如果写“w”,那么打开文件为只写打开,如果文件不存在则创建文件,如果文件存在则清空文件后打开 
-  也就是说fopen的第二个参数“w” = open的第二个参数传:O_WRONLY | O_CREAT | O_TUNC 
 
-  
 
-  
 
-  
-  参数3 -  当第二个参数flags里面拥有O_CREAT属性的时候,此时要求传入第3个参数mode,用来表示文案创建时候的权限,故一般传0664,0666这样的数据 
-  创建文件时未传入权限值,则会以一个随机的权限创建文件 
 
-  
-  返回值 -  成功打开文件,返回该值的描述符(int类型) 
-  失败返回-1 
-  open函数返回的文件描述符的取值规则为:最小未使用位置 例:原本打开文件为 0 1 2 3 4 5 此时关闭3号文件,那么描述符就为 : 0 1 2 4 5 此时,若我们又打开了一个新文件,那么描述符就有:012345 
 
-  
-  不使用文件时关闭文件 -  close(fd) 
 
-  
 
-  
 
-  
-  文件IO的输入输出函数 -  write -  ssize_t write(int fd, const void *buf, size_t count); 
-  参数1 -  文件描述符 
 
-  
-  参数2 -  存放有准备写入文件中的数据的地址 
 
-  
-  参数3 -  准备写入的数据的数量 
-  注意 -  该函数是一个数据流函数(字符) 
 
-  
 
-  
-  返回值 -  成功写入数据,返回写入数据的数量 
-  失败返回-1 -  失败原因:只可能是描述符突然关闭 
 
-  
 
-  
-  阻塞型函数 -  将输入写入的数据,若存满,则会阻塞 直到文件出现空闲内存为止 
 
-  
 
-  
-  read -  ssize_t read(int fd, void *buf, size_t count); 
-  功能描述 -  将fd描述的文件中,最多读取count个字节的数据,然后写入buf中 
 
-  
-  参数1 -  文件描述符号 
 
-  
-  参数2 -  存放读取到的数据的地址 
 
-  
-  参数3 -  最多读取的数据的数量 
 
-  
-  注意 -  根据文件描述符的不同,read的行为模式不同,有阻塞的也有非阻塞的 
-  描述符 -  描述普通文件时:read非阻塞 
-  描述终端时:read阻塞 
-  描述管道文件时:read阻塞 
-  描述套接字时:read阻塞 
 
-  
 
-  
-  返回值 -  成功返回读取到的数据的数量 
-  失败返回-1 
-  没有读取到数据返回0 
-  read实际上根据描述符的文件的不同,行为模式的不同,返回值的意义都是不同的 
 
-  
-  注意 -  fread只要读取到文件结束符就会返回0 而read读取到文件结束符不会返回0 只有read读取一次之后发现没有读取到数据才会返回0 
 
-  
 
-  
 
-  
-  3个特殊文件描述符 -  标准输入流 -  STDIN_FILENO 或 0 
 
-  
-  标准输出流 -  STDOUT_FILENO 或 1 
 
-  
-  标准错误流 -  STDERR_FILENO 或 2 
 
-  
 
-  
-  重定向函数 -  dup2 -  int dup2 = (int oldfd, int newfd); 
-  目标:将标准错误流 STDERR_FILENO, 重定向到err.txt这个文件中 -  dup2(err.txt, STDERR_FILENO); 
-  解析: -  filearr[n] = {&stdin, &stdout, &stderr}; 
-  代码int fd = open("./err.txt", ...);执行后filearr将会在最小未使用位置上放置打开的文件 
-  filearr[n] = {&stdin, &stdout, &stderr, &err.xtxt}; 
-  当执行代码dup2(err.txt, STDERR_FILENO); -  本质上相当于执行 filarr[STDERR_FILENO] = filearr[fd] (同等于filarr[2] = filearr[3]) 
 
-  
-  filearr更新为filearr[n] = {&stdin, &stdout, &err.txt, &err.txt} -  此时&stderr被覆盖 
 
-  
-  perror()函数默认调用STDERR_FILEENO -  此时2位置上的文件为err.txt实现了错误信息输出到自定文件中 
 
-  
 
-  
 
-  
 
-  
-  dup -  int dup(int older); 
-  功能描述 -  将odler,在filearr中的最小未使用位置上,做备份,被返回该位置的值,作为描述符 
-  原本:filearr[n] = {&stdin, &stdout, &stderr}; 
-  执行:dup(STDERR_FILENO); 
-  更新后:filearr[n] = {&stdin, &stdout, &stderr, &stderr};(dup 返回3) -  当文件2被覆盖后执行dup2(3, STDERR_FILEENO) 
-  即可恢复标准错误流的指向 
 
-  
 
-  
 
-  
 
-  
-  判断文件是否存在,是否拥有用户可读可写可执行权限 -  功能描述 -  判断pathname文件是否拥有mode权限 
 
-  
-  access -  int access(const char *pathname, int mode); 
-  功能描述 -  判断pathname文件,是否拥有mode权限 
 
-  
-  参数 pathname -  准备判断的文件路径名 
 
-  
-  参数 mode -  F_OK -  判断文件是否存在 
 
-  
-  R_OK -  判断文件是否拥有用户可读权限 
 
-  
-  W_OK -  判断文件是否拥有用户可写权限 
 
-  
-  X_OK -  判断文件是否拥有用户可执行权限 
 
-  
 
-  
-  返回值 -  成功判断返回0,失败返回-1 
 
-  
 
-  
 
-  
-  判断文件的类型以及文件是否拥有UGO的3项权限 -  stat,fstat,lstat -  stat -  int stat(const char *pathname, struct stat *statbuf); 
 
-  
-  fstat -  int fstat(int fd, struct stat *statbuf); 
 
-  
-  lstat -  int lstat(const char *pathname, struct stat *statbuf); 
 
-  
-  以上3个函数全都是用来判断文件类型或者判断文件是否拥有某项权限的 -  区别在于: 
-  stat和fstat -  一个使用文件路径名锁定文件,一个使用文件描述符锁定文件 
 
-  
-  stat和lstat -  他俩只有在判断符号链接文件的时候才有区别 
 
-  
-  当符号链接文件传递给stat的时候,stat会获取到符号链接文件所引用的源文件的属性和类型 
-  当符号链接文件传递给lstat的时候,无论符号连接文件引用的源文件是什么类型,获取到的都是符号连接文件本身的属性和文件 
 
-  
-  参数 pathname -  准备获取属性和类型的文件的路径名 
 
-  
-  参数 statbuf -  用来存放获取到的文件的属性和类型的地址,文件有哪些属性,类型怎么判断。 详见statbuf,结构体如下 
 
-  
-  struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* Inode number */ mode_t st_mode; /* File type and mode */ nlink_t st_nlink; /* Number of hard links */ uid_t st_uid; /* User ID of owner */ gid_t st_gid; /* Group ID of owner */ dev_t st_rdev; /* Device ID (if special file) */ off_t st_size; /* Total size, in bytes */ blksize_t st_blksize; /* Block size for filesystem I/O */ blkcnt_t st_blocks; /* Number of 512B blocks allocated */ }; 注释说的很明确,文件类型和属性,都在st_mode里面放着 
 
-  
-  如果通过stat函数判断一个文件是否拥有某项权限 -  根据 :一个数 | 另一个数 如果没有发生改变的话,则表明该数拥有被按位或的数 -  权限的宏定义如下 S_ISUID 04000 set-user-ID bit S_ISGID 02000 set-group-ID bit (see below) S_ISVTX 01000 sticky bit (see below) S_IRWXU 00700 owner has read, write, and execute permission S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 group has read, write, and execute permission S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 others (not in group) have read, write, and execute permission S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permission S_IXOTH 00001 others have execute permission 
 
-  
 
-  
-  如何判断一个文件的类型 -  使用以下几个带参宏,来判断文件的类型 -  S_ISREG(st_mode) is it a regular file? 
-  S_ISDIR(st_mode) directory? 
-  S_ISCHR(st_mode) character device? 
-  S_ISBLK(st_mode) block device? 
-  S_ISFIFO(st_mode) FIFO (named pipe)? 
-  S_ISLNK(st_mode) symbolic link? (Not in POSIX.1-1996.) 
-  S_ISSOCK(st_mode) socket? (Not in POSIX.1-1996.) 
 
-  
-  只要将st_mode 传入一下几个带参宏里面,就能得到结果 
-  比如说:如果是一个普通文件,那么只哟 S_ISREG(st_mode) 返回1,其他所有带参宏返回0 
 
-  
 
-  
-  设置掩码的函数 -  什么叫做掩码:和文件权限相关一个数据 顾名思义:就是需要遮掩掉某些值的一个码 其实,我们在创建文件时候,我们所指定的权限值,并不是这个文件的最终权限值,而是需要剔除掉掩码当中所设定的哪些权限后,才是文件的最终权限值 -  如果当前掩码为 0111 -  文件创建权限为 0666,文件最终权限是 0666 
 
-  
-  如果当前掩码设置为 0333 -  文件创建权限为 0666 ,文件最终权限为 0444 
 
-  
-  当前掩码设置的是 0111 -  如果,文件创建的时候,创建权限为 0777 ,所以文件最终权限需要扣除掩码的权限,最终权限为 0666 
 
-  
 
-  
-  mode_t umask(mode_t cmask); -  功能描述:设置当前程序掩码的值 
-  参数 cmask:掩码值 
 
-  
 
-  
 
-  
作业: 实现目录下所有文件的复制
#include <myhead.h>
#include <dirent.h>int main(int argc, const char *argv[])
{//首先判断目标文件夹是否存在
//	if(access("./a", F_OK) == -1)
//	{//	}//打开a目录struct dirent *dir;DIR *dirp = opendir("./a");if(NULL == dirp){perror("opendir");return -1;}int ret = 0;while(NULL != (dir = readdir(dirp))){
/*		char tar_path[32] = {0};strcat(tar_path, "/");char org_path[32] = {0};strcat(org_path, "/");strcat(tar_path, dir -> d_name);
*/		if(strcmp(dir -> d_name, ".") == 0 || strcmp(dir -> d_name, "..") == 0){continue;}chdir("./a");int rfd = open(dir -> d_name, O_RDONLY);chdir("..");chdir("./b");int wfd = open(dir -> d_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);while(1){char arr[3] = {0};ret = read(rfd, arr, 3);if(ret <= 0){break;}write(wfd, arr, ret);}chdir("..");close(rfd);close(wfd);}closedir(dirp);return 0;
}
