man 命令后面跟着两个参数的具体含义和用法数字1Linux命令 数字2系统调用 数字3标准C库 如 man 1 ls man 2 open1.open一个进程内多次 open 打开同一个文件在内存中并不会存在多份动态文件。一个进程内多次 open 打开同一个文件不同文件描述符所对应的读写位置偏移量是相互独立的。加入了O_APPEND标志后分别写已经变成了接续写。int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); flags 这三个是文件访问权限标志传入的 flags 参数中必须要包含其中一种标志而且只能包含一种 O_RDONLYRO O_WRONLYWO O_RDWRRW O_CREAT文件不存在则创建第 3 个参数只有在使用了 O_CREAT 或 O_TMPFILE 标志时才有效。 O_DIRECTORY不是一个目录则调用 open 失败 O_EXCL一般结合 O_CREAT 标志一起使用文件已经存在则 open 函数返回错误。 O_NOFOLLOW指向的是一个符号链接将不对其进行解引用直接返回错误。 O_TRUNC将文件原本的内容全部丢弃 O_APPENDwrite()函数对文件进行写文件当前位置偏移量移动到文件末尾。 mode 指定新建文件的访问权限。 当 flags 参数中包含 O_CREAT 或 O_TMPFILE 标志时才有效O_TMPFILE 标志用于创建一个临时文件2.writessize_t write(int fd, const void *buf, size_t count); fd文件描述符。 buf指定写入数据对应的缓冲区。 count指定写入的字节数3.readssize_t read(int fd, void *buf, size_t count); fd文件描述符。与 write 函数的 fd 参数意义相同。 buf指定用于存储读取数据的缓冲区。 count指定需要读取的字节数。 返回值如果读取成功将返回读取到的字节数4.closeint close(int fd); fd文件描述符需要关闭的文件所对应的文件描述符。 返回值如果成功返回 0如果失败则返回-1。5.lseek操作文件偏移量off_t lseek(int fd, off_t offset, int whence); fd文件描述符。 offset偏移量以字节为单位。 whence SEEK_SET读写偏移量将指向 offset 字节位置处从文件头部开始算 SEEK_CUR读写偏移量将指向当前位置偏移量 offset 字节位置处offset 可以为正、也可以为 负如果是正数表示往后偏移如果是负数则表示往前偏移 SEEK_END读写偏移量将指向文件末尾 offset 字节位置处同样 offset 可以为正、也可以为负 如果是正数表示往后偏移、如果是负数则表示往前偏移。 返回值成功将返回从文件头部开始算起的位置偏移量字节为单位也就是当前的读写位置发生 错误将返回-1。6._exit()和_Exit()系统调用退出函数_exit()和_Exit()两者等价用来终止进程这 2 个函数都是系统调用7.exit()函数 标准C库退出函数执行清理再调用系统调用的退出函数exit()是一个标准 C 库函数执行 exit()会执行一些清理工作最后调用_exit()函数。exit()函数。exit()会更加上层封装了一些善后处理工作最终都会调用系统调用_exit()和_Exit()。8.空洞文件#include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include stdio.h #include string.h #include stdlib.h int main(void) { int fd; int ret; char buffer[1024]; int i; /* 打开文件 */ fd open(./hole_file, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (-1 ret) { perror(lseek error); goto err; } /* 将文件读写位置移动到偏移文件头 4096 个字节(4K)处 */ ret lseek(fd, 4096, SEEK_SET); if (-1 ret) { perror(lseek error); goto err; } /* 初始化 buffer 为 0xFF */ memset(buffer, 0xFF, sizeof(buffer)); /* 循环写入 4 次每次写入 1K */ for (i 0; i 4; i) { ret write(fd, buffer, sizeof(buffer)); if (-1 ret) { perror(write error); goto err; } } ret 0; err: /* 关闭文件 */ close(fd); exit(ret); }lseek允许文件偏移量超出文件长度譬如有一个 test_file该文件的大小是 4K也就是 4096 个字节如果通过 lseek 系统调用将该文件的读写偏移量移动到偏移文件头部 6000 个字节处接下来使用write会从6000字节开始写4096~6000 字节之间出现了一个空洞这部分区域就被称为文件空洞那么相应的该文件也被称为空洞文件。文件空洞部分实际上并不会占用任何物理空间。9.dup复制文件描述符由系统分配可以实现接续写int dup(int oldfd); oldfd需要被复制的文件描述符。 返回值成功时将返回一个新的文件描述符由操作系统分配失败将返回-1并设置errno值 /* 复制文件描述符 */ fd2 dup(fd1); if (-1 fd2) { perror(dup error); ret -1; goto err1; }10.dup2 指定一个文件描述符int dup2(int oldfd, int newfd); oldfd需要被复制的文件描述符。 newfd指定一个文件描述符需要指定一个当前进程没有使用到的文件描述符。 返回值成功时将返回一个新的文件描述符失败将返回-1并且会设置 errno 值 /* 复制文件描述符 */ fd2 dup2(fd1, 100); if (-1 fd2) { perror(dup error); ret -1; goto err1; }11.原子操作(1)O_APPEND 实现原子操作先定位到文件末尾然后写防止覆盖。(2)pread()和 pwrite()pread()和 pwrite()都是系统调用与read()、write()函数的作用一样区别在于 pread()和 pwrite()可用于实现原子操作ssize_t pread(int fd, void *buf, size_t count, off_t offset); ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); pread 相当于调用 lseek 后再调用 read pwrite 相当于调用 lseek 后再调用 writ(3)O_EXCL将“判断文件是否存在、创建文件”这两个步骤合成为一个原子操作12.fcntl可通过man 2 fcntl命令查看int fcntl(int fd, int cmd, ... /* arg */ ) fd文件描述符。 cmd操作命令。 ⚫ 复制文件描述符cmdF_DUPFD 或 cmdF_DUPFD_CLOEXEC ⚫ 获取/设置文件描述符标志cmdF_GETFD 或 cmdF_SETFD ⚫ 获取/设置文件状态标志cmdF_GETFL 或 cmdF_SETFL ⚫ 获取/设置异步 IO 所有权cmdF_GETOWN 或 cmdF_SETOWN ⚫ 获取/设置记录锁cmdF_GETLK 或 cmdF_SETLK …fcntl 函数是一个可变参函数第三个参数需要根据不同的 cmd 来传入对应的实参配合 cmd 来使 用。13.ioctl 函数int ioctl(int fd, unsigned long request, ...); fd文件描述符。 request此参数与具体要操作的对象有关没有统一值表示向文件描述符请求相应的操作 ...此函数是一个可变参函数根据 request 参数来决定配合 request 来使用。
一、Linux C编程笔记——文件IO(属于系统调用)
man 命令后面跟着两个参数的具体含义和用法数字1Linux命令 数字2系统调用 数字3标准C库 如 man 1 ls man 2 open1.open一个进程内多次 open 打开同一个文件在内存中并不会存在多份动态文件。一个进程内多次 open 打开同一个文件不同文件描述符所对应的读写位置偏移量是相互独立的。加入了O_APPEND标志后分别写已经变成了接续写。int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); flags 这三个是文件访问权限标志传入的 flags 参数中必须要包含其中一种标志而且只能包含一种 O_RDONLYRO O_WRONLYWO O_RDWRRW O_CREAT文件不存在则创建第 3 个参数只有在使用了 O_CREAT 或 O_TMPFILE 标志时才有效。 O_DIRECTORY不是一个目录则调用 open 失败 O_EXCL一般结合 O_CREAT 标志一起使用文件已经存在则 open 函数返回错误。 O_NOFOLLOW指向的是一个符号链接将不对其进行解引用直接返回错误。 O_TRUNC将文件原本的内容全部丢弃 O_APPENDwrite()函数对文件进行写文件当前位置偏移量移动到文件末尾。 mode 指定新建文件的访问权限。 当 flags 参数中包含 O_CREAT 或 O_TMPFILE 标志时才有效O_TMPFILE 标志用于创建一个临时文件2.writessize_t write(int fd, const void *buf, size_t count); fd文件描述符。 buf指定写入数据对应的缓冲区。 count指定写入的字节数3.readssize_t read(int fd, void *buf, size_t count); fd文件描述符。与 write 函数的 fd 参数意义相同。 buf指定用于存储读取数据的缓冲区。 count指定需要读取的字节数。 返回值如果读取成功将返回读取到的字节数4.closeint close(int fd); fd文件描述符需要关闭的文件所对应的文件描述符。 返回值如果成功返回 0如果失败则返回-1。5.lseek操作文件偏移量off_t lseek(int fd, off_t offset, int whence); fd文件描述符。 offset偏移量以字节为单位。 whence SEEK_SET读写偏移量将指向 offset 字节位置处从文件头部开始算 SEEK_CUR读写偏移量将指向当前位置偏移量 offset 字节位置处offset 可以为正、也可以为 负如果是正数表示往后偏移如果是负数则表示往前偏移 SEEK_END读写偏移量将指向文件末尾 offset 字节位置处同样 offset 可以为正、也可以为负 如果是正数表示往后偏移、如果是负数则表示往前偏移。 返回值成功将返回从文件头部开始算起的位置偏移量字节为单位也就是当前的读写位置发生 错误将返回-1。6._exit()和_Exit()系统调用退出函数_exit()和_Exit()两者等价用来终止进程这 2 个函数都是系统调用7.exit()函数 标准C库退出函数执行清理再调用系统调用的退出函数exit()是一个标准 C 库函数执行 exit()会执行一些清理工作最后调用_exit()函数。exit()函数。exit()会更加上层封装了一些善后处理工作最终都会调用系统调用_exit()和_Exit()。8.空洞文件#include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include stdio.h #include string.h #include stdlib.h int main(void) { int fd; int ret; char buffer[1024]; int i; /* 打开文件 */ fd open(./hole_file, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (-1 ret) { perror(lseek error); goto err; } /* 将文件读写位置移动到偏移文件头 4096 个字节(4K)处 */ ret lseek(fd, 4096, SEEK_SET); if (-1 ret) { perror(lseek error); goto err; } /* 初始化 buffer 为 0xFF */ memset(buffer, 0xFF, sizeof(buffer)); /* 循环写入 4 次每次写入 1K */ for (i 0; i 4; i) { ret write(fd, buffer, sizeof(buffer)); if (-1 ret) { perror(write error); goto err; } } ret 0; err: /* 关闭文件 */ close(fd); exit(ret); }lseek允许文件偏移量超出文件长度譬如有一个 test_file该文件的大小是 4K也就是 4096 个字节如果通过 lseek 系统调用将该文件的读写偏移量移动到偏移文件头部 6000 个字节处接下来使用write会从6000字节开始写4096~6000 字节之间出现了一个空洞这部分区域就被称为文件空洞那么相应的该文件也被称为空洞文件。文件空洞部分实际上并不会占用任何物理空间。9.dup复制文件描述符由系统分配可以实现接续写int dup(int oldfd); oldfd需要被复制的文件描述符。 返回值成功时将返回一个新的文件描述符由操作系统分配失败将返回-1并设置errno值 /* 复制文件描述符 */ fd2 dup(fd1); if (-1 fd2) { perror(dup error); ret -1; goto err1; }10.dup2 指定一个文件描述符int dup2(int oldfd, int newfd); oldfd需要被复制的文件描述符。 newfd指定一个文件描述符需要指定一个当前进程没有使用到的文件描述符。 返回值成功时将返回一个新的文件描述符失败将返回-1并且会设置 errno 值 /* 复制文件描述符 */ fd2 dup2(fd1, 100); if (-1 fd2) { perror(dup error); ret -1; goto err1; }11.原子操作(1)O_APPEND 实现原子操作先定位到文件末尾然后写防止覆盖。(2)pread()和 pwrite()pread()和 pwrite()都是系统调用与read()、write()函数的作用一样区别在于 pread()和 pwrite()可用于实现原子操作ssize_t pread(int fd, void *buf, size_t count, off_t offset); ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); pread 相当于调用 lseek 后再调用 read pwrite 相当于调用 lseek 后再调用 writ(3)O_EXCL将“判断文件是否存在、创建文件”这两个步骤合成为一个原子操作12.fcntl可通过man 2 fcntl命令查看int fcntl(int fd, int cmd, ... /* arg */ ) fd文件描述符。 cmd操作命令。 ⚫ 复制文件描述符cmdF_DUPFD 或 cmdF_DUPFD_CLOEXEC ⚫ 获取/设置文件描述符标志cmdF_GETFD 或 cmdF_SETFD ⚫ 获取/设置文件状态标志cmdF_GETFL 或 cmdF_SETFL ⚫ 获取/设置异步 IO 所有权cmdF_GETOWN 或 cmdF_SETOWN ⚫ 获取/设置记录锁cmdF_GETLK 或 cmdF_SETLK …fcntl 函数是一个可变参函数第三个参数需要根据不同的 cmd 来传入对应的实参配合 cmd 来使 用。13.ioctl 函数int ioctl(int fd, unsigned long request, ...); fd文件描述符。 request此参数与具体要操作的对象有关没有统一值表示向文件描述符请求相应的操作 ...此函数是一个可变参函数根据 request 参数来决定配合 request 来使用。