【APUE】文件 I/O 操作

举报
韩曙亮 发表于 2022/01/11 00:47:26 2022/01/11
【摘要】 博客地址 : http://blog.csdn.net/shulianghan/article/details/46980271 一. 文件打开关闭操作相关函数介绍 1. open 函数 (1) open 函数简介 open 函数解析 :  -- 函数定义 :  #incl...


博客地址 : http://blog.csdn.net/shulianghan/article/details/46980271






一. 文件打开关闭操作相关函数介绍



1. open 函数



(1) open 函数简介


open 函数解析

-- 函数定义


  
  1. #include <fcntl.h>
  2. int
  3. open(const char *path, int oflag, ...);


-- 函数作用 : 打开或者创建一个文件;

-- 返回值 : 打开文件成功, 返回文件描述符; 如果失败, 返回 -1; 返回的文件描述符是最小的未用描述符值



(2) open 函数参数简介


参数解析

-- const char *path : 要打开或者创建的文件名;

-- int oflag : 函数选项, 可以是多个常量进行 "或" 运算;

-- 第三参数 : 对于打开文件来说是用不到第三参数的, 如果需要创建文件, 则需要指定第三参数;


int oflag 参数必选常量解析 : 下面的三个常量必须只能且只能指定一个;

-- O_RDONLY : 打开的文件只能读取, 没有写权限;

-- O_WRONLY : 打开的文件只能写入, 没有读权限;

-- O_RDWR : 打开的文件既能读取, 也能写入, 有双权限;


int oflag 参数可选常量解析

-- O_APPEND : 每次写入都追加到文件末尾;

-- O_CREATE : 如果文件不存在, 就创建, 如果有这个参数, 就需要使用第三个参数来指定创建文件时的参数;

-- O_EXCL : 指定该参数, 同时指定 O_CREATE, 文件如果存在就会报错;

-- O_TRUNC : 如果文件存在, 并且有写权限的前提下, 打开时会将其内容清空, 从新写入;

-- O_NOCTTY : 如果第一个参数文件路径指向一个终端设备, 不能将该设备作为进程的控制终端;

-- O_NONBLOCK : 如果文件路径指向一个 FIFO, 特殊文件块, 字符特殊文件, 同时指定该选项, 文件的IO操作设置为非阻塞模式;


int oflag 同步参数可选常量解析 : 

-- O_DSYNC : 每次 write 操作之前等待 IO 完成, 如果写操作不影响读取刚写入的数据, 则不等待文件属性被更新;

-- O_RSYNC : 读操作时等待, 直到所有的写操作都完成;

-- O_SYNC : 每次写都要等待物理 IO 操作完成, 包括 write 引起的文件属性更新; 即 数据和属性同步更新;



2. create 函数



(1) create 函数简介


create 函数简介

-- 函数定义


  
  1. #include <fcntl.h>
  2. int
  3. creat(const char *path, mode_t mode);
-- 返回值 : 返回只写打开的文件描述符, 出错返回 -1;

-- 等效函数 : open(path_name, O_WRONLY | O_CREATE | O_TRUNC, mode);

-- mode_t mode 参数 : 指定文件的所有者;


(2) create 函数局限性


create 局限性

-- 只写 : create 函数只能以只写方式打开创建的文件;

-- 读取新文件方法 : 先 create 创建只写文件, 再调用 close 函数, 再调用 open 方法打开文件读取文件;

-- 创建只读文件 : open(path_name, O_RDWR | O_CREATE | O_TRUNC, mode);



3. close 函数



函数简介

-- 函数定义


  
  1. #include <unistd.h>
  2. int
  3. close(int fildes);
作用 进程 记录锁

-- 关于进程 : 进程终止时, 内核会自动关闭该进程中打开的所有文件, 很多情况下都会使用关闭进程隐式关闭文件;



二. 文件偏移操作相关函数介绍



1. lseek 函数



(1) lseek 函数简介


lseek 函数简介

-- 函数定义


  
  1. #include <unistd.h>
  2. off_t
  3. lseek(int fildes, off_t offset, int whence);

-- 作用 : 显式的为一个打开的文件设置偏移量;

-- 返回值 : 如果设置偏移量成功, 返回新的偏移量;


(2) 文件偏移量简介


文件偏移量 :  

当前文件偏移量

-- 默认偏移量 : 打开一个文件时默认 当前文件偏移量 是0, 除非指定 O_APPEND 选项;

-- 偏移量的值 : 普通文件偏移量必须是非负整数; 对于某些设备文件允许存在负数偏移量, 因此判断是否可 lseek 时, 要判断返回的文件偏移量是否 == -1;


(3) int where 参数简介


where 参数简介

-- SEEK_SET : 将文件偏移量设置为 0 + offset;

-- SEEK_CUR : 将文件偏移量设置为 当前位移 + offset;

-- SEEK_END : 将文件偏移量设置为 文件长度 + offset;


(4) lseek 源码示例


源码示例


  
  1. /*************************************************************************
  2. > File Name: fun_lseek.c
  3. > Author: octopus
  4. > Mail: octopus_truth.163.com
  5. > Created Time: 三 7/22 07:46:59 2015
  6. ************************************************************************/
  7. #include<stdio.h>
  8. #include<unistd.h>
  9. #include<stdlib.h>
  10. int main(int argc, char * argv[])
  11. {
  12. /*
  13. * 设置标准输入文件的 "当前文件偏移量",
  14. * 设置为当前的位置 + 0;
  15. */
  16. if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
  17. printf("lseek 结果 -1, 该文件不能lseek\n");
  18. else
  19. printf("该文件可以执行 lseek 方法\n");
  20. exit(0);
  21. }

编译执行


  
  1. localhost:file octopus$ gcc fun_lseek.c
  2. localhost:file octopus$ ./a.out
  3. 该文件可以执行 lseek 方法


(5) 文件空洞


文件空洞形成

-- 文件偏移量作用 : 文件偏移量是记录在内核中, 不引起 IO 操作, 这个偏移量主要用于执行下一次的 IO 操作;

-- 空洞形成 : 如果文件偏移量大于当前文件长度, 下一次写操作会直接加长文件, 并在中间形成一个 "文件空洞";

-- 磁盘占用情况 : 文件空洞是不占用磁盘存储区的, 写入数据超出文件长度时, 新写入的数据会重新分配磁盘块, 之间的一段文件空洞不会占用磁盘空间;



三. 文件读写操作相关函数介绍



1. read 函数



函数简介

-- 函数内容


  
  1. #include <sys/types.h>
  2. #include <sys/uio.h>
  3. #include <unistd.h>
  4. ssize_t
  5. read(int fildes, void *buf, size_t nbyte);
作用

-- 返回值 : 如果 read 操作成功, 返回读取到得字节数, 如果失败, 返回 -1;



2. write 函数



函数简介

-- 函数内容


  
  1. #include <unistd.h>
  2. ssize_t
  3. write(int fildes, const void *buf, size_t nbyte);


-- 函数作用 : 将 buf 字符串的前 nbyte 个字节数据写入 files 文件标示符 代表的文件中;

-- 返回值 : 若成功, 返回已写的字节数, 如果失败返回 -1;



3. write read 函数示例



源码示例

-- 源码 : 


  
  1. /*************************************************************************
  2. > File Name: fun_read_write.c
  3. > Author: Han Shuliang
  4. > Mail: octopus_truth@163.com
  5. > Created Time: 五 7/29 15:00:18 2016
  6. ************************************************************************/
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #define SIZE 1024
  10. int main(int argc, char * argv[])
  11. {
  12. int n;
  13. char buf[SIZE];
  14. //读取标准输入流中的数据到 buf 字节数组中
  15. while ((n = read(STDIN_FILENO, buf, SIZE)) > 0)
  16. //将 buf 字节数组中的数据写出到 标准输出流中
  17. if(write(STDOUT_FILENO, buf, n)!= n)
  18. printf("写出内容出错");
  19. if(n < 0)
  20. printf("读取过程出错");
  21. return 0;
  22. }


-- 执行结果 : 


  
  1. bogon:file octopus$ gcc fun_read_write.c
  2. bogon:file octopus$ ./a.out
  3. Han Shuliang
  4. Han Shuliang
  5. CSDN
  6. CSDN
  7. ^C
  8. bogon:file octopus$



4. 函数综合示例




  
  1. /*************************************************************************
  2. > File Name: fun_read.c
  3. > Author: octopus
  4. > Mail: octopus_truth.163.com
  5. > Created Time: 一 7/27 07:09:36 2015
  6. ************************************************************************/
  7. #include <stdio.h>
  8. #include <sys/types.h> // ... read() 头文件
  9. #include <sys/uio.h> // ... read() 头文件
  10. #include <unistd.h> // ... read() write() 函数头文件
  11. #include <stdarg.h> // va_list 可变参数操作头文件
  12. #include <string.h> // strlen strcat 方法的头文件
  13. #include <errno.h> // errno 的头文件
  14. #include <stdlib.h> // exit() 方法的头文件
  15. #include <fcntl.h> // open() 函数的头文件
  16. #define MAXLINE 4096
  17. #define MAXWORD 20
  18. void err_sys(const char *fmt, ...);
  19. int main(int argc, char * argv[])
  20. {
  21. char *buf = "abcdefg\n";
  22. char buf_read[MAXWORD];
  23. int fd;
  24. int creat_result;
  25. int write_size;
  26. int close_result;
  27. int read_size;
  28. //创建一个文件, 使用打开方式, 如果文件不存在, 就重创建并打开
  29. if( ( fd = open("file_read_write.file", O_WRONLY | O_CREAT | O_TRUNC) ) == -1)
  30. err_sys("创建文件出错");
  31. //向文件中写出数据
  32. if( (write_size = write(fd, buf, strlen(buf))) == -1)
  33. err_sys("向文件写出数据出错");
  34. if( (close_result = close(fd)) == -1)
  35. err_sys("关闭文件出错");
  36. if( (fd = open("file_read_write.file", O_RDONLY)) == -1)
  37. err_sys("打开文件出错");
  38. //从文件中读取文件内容
  39. if( (read_size = read(fd, buf_read, strlen(buf)) ) == -1)
  40. err_sys("读取文件出错");
  41. if( (close_result = close(fd)) == -1)
  42. err_sys("关闭文件出错");
  43. printf("文件中得内容 : %s \n", buf_read);
  44. }
  45. static void err_doit(int errnoflag, int error, const char* fmt, va_list ap)
  46. {
  47. char buf[MAXLINE];
  48. //将 ap 可变参数使用 fmt 格式, 放置 MAXLINE 个字符到 buf 缓冲中
  49. vsnprintf(buf, MAXLINE, fmt, ap);
  50. /*
  51. * 如果需要错误信息, 根据错误号获取标准错误信息, 将该信息添加到 buf 缓冲中
  52. * strlen 作用 : 获取字符串长度
  53. * strerror 作用 : 根据错误号获取错误信息
  54. */
  55. if(errnoflag)
  56. snprintf(buf + strlen(buf), MAXLINE - strlen(buf), ": %s", strerror(errno));
  57. //在 buf 字符串后添加换行符号
  58. strcat(buf, "\n");
  59. //刷新标准输出流
  60. fflush(stdout);
  61. //将标准错误输出添加到 buf 缓冲区中
  62. fputs(buf, stderr);
  63. //刷新所有缓冲区
  64. fflush(NULL);
  65. }
  66. void err_sys(const char *fmt, ...)
  67. {
  68. va_list ap;
  69. va_start(ap, fmt);
  70. err_doit(1, errno, fmt, ap);
  71. va_end(ap);
  72. exit(0);
  73. }

执行结果


  
  1. octopus-2:file octopus$ ls
  2. fun_lseek.c fun_lseek_hole.c fun_read_write.c
  3. octopus-2:file octopus$ gcc fun_read_write.c
  4. octopus-2:file octopus$ sudo ./a.out
  5. Password:
  6. 文件中得内容 : abcdefg
  7. octopus-2:file octopus$ ls
  8. a.out file_read_write.file fun_lseek.c fun_lseek_hole.c fun_read_write.c
  9. octopus-2:file octopus$




四. 文件读写原子操作相关函数介绍




1. pread 函数




pread 函数

-- 1. 函数内容 :


  
  1. #include <unistd.h>
  2. ssize_t pread(int fd, void *buf, size_t count, off_t offset);

-- 2. 函数作用 : 读取文件描述符 fd 对应的文件, 返回读取到的文件字节个数, 读取到文件结尾 返回 0, 出现错误返回 -1;

-- 3. 函数返回值 : 返回读取文件的字节数, 读取到结尾返回 0, 出错返回 -1;


pread 与 read 方法作用

-- 1. 等价执行流程 : pread 方法等价于 先调用 lseek 方法,  再调用 read 方法;

-- 2. 与等价流程的区别 : ① 执行 pread 方法时, 先定位 后 读取 的两个操作, 不能中断; ② 文件指针 不更新;



2. pwrite 函数



pwrite 函数 : 

-- 1. 函数内容 : 


  
  1. #include <unistd.h>
  2. ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);


-- 2. 函数作用 : 写出数据到指定的位置;

-- 3. 函数返回值 : 返回写出的字节数, 出现错误返回 -1;

-- 4. 等价操作 : pwrite 等价于 lseek 和 write 操作;








3. pread 和 pwrite 函数示例




函数示例过程 : 

-- 1. 打开文件, 如果没有就创建;

-- 2. 写出 a ~ z 26个子母;

-- 3. 读取文件 10 ~ 15 个字节;

-- 4. 向第 10 个字节处写出 "00000" 字符串;


函数示例 : 

-- 代码 : 


  
  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. int main(int argc, char **argv)
  6. {
  7. printf("main : \n");
  8. int file_fd, write_result;
  9. char * buffer = "abcdefghigklmnopqrstuvwxyz";
  10. file_fd = open("5.pread_write.txt", O_RDWR | O_APPEND | O_CREAT);
  11. printf("file_fd = %d\n", file_fd);
  12. write_result = write(file_fd, buffer, strlen(buffer));
  13. printf("write success, count = %d\n", write_result);
  14. return 0;
  15. }


.



.




.













.













.












.


文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/46980271

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。