• 文件流和文件描述符互相转换


    前言

            假如,你正在升级一个成熟的项目,其中使用的是文件流,你需要使用文件描述符中的某些功能,或者反过来,这时候,就需要他们之间的互相转换操作。

    涉及的头文件和函数

    1. #include
    2. #include
    3. #include
    4. int fileno(FILE* stream);
    5. FILE* fdopen(int fd,const char *mode);
    6. FILE *fopen(const char *path, const char *mode);
    7. int fcntl(int fd, int cmd, ... /* arg */ );

    mode参数取值和fopen的mode相同:r+等同于O_RDWR;

    r      打开文本文件,用于读。流被定位于文件的开始。

    r+     打开文本文件,用于读写。流被定位于文件的开始。

    w      将文件长度截断为零,或者创建文本文件,用于写。流被定位于文件的开始。

    w+     打开文件,用于读写。如果文件不存在就创建它,否则将截断它。流被定位于文件的开始。

    a      打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。流被定位于文件的末尾。

    a+     打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。读文件的初始位置是文件的开始,但是输出总是被追加到文件的末尾。
     

    一 文件流转文件描述符

    在该实例中需要使用fcntl设置为非阻塞模式,操作步骤如下:

    1 获取文件的flags,即open函数的第二个参数:
    flags = fcntl(fd,F_GETFL,0);
    2、设置文件的flags:
    fcntl(fd,F_SETFL,flags);
    3、增加文件的某个flags,比如文件是阻塞的,想设置成非阻塞:
    flags = fcntl(fd,F_GETFL,0);
    flags |= O_NONBLOCK;
    fcntl(fd,F_SETFL,flags);
    4、取消文件的某个flags,比如文件是非阻塞的,想设置成为阻塞:
    flags = fcntl(fd,F_GETFL,0);
    flags &= ~O_NONBLOCK;
    fcntl(fd,F_SETFL,flags);

    源码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. char *msg = "I'm a student\n";
    9. char buf[100000];
    10. int main(int argc,char *argv[])
    11. {
    12. char *name = "/dev/kmsg";
    13. FILE *p;
    14. int len = 0;
    15. int fd = 0;
    16. int flags;
    17. p = fopen(name,"r+");
    18. if(p == NULL){
    19. perror("open");
    20. return -1;
    21. }
    22. fd = fileno(p);
    23. if(fd < 0){
    24. perror("fdopen");
    25. exit(-1);
    26. }
    27. flags = fcntl(fd,F_GETFL,0);
    28. flags |= O_NONBLOCK;
    29. fcntl(fd,F_SETFL,flags);
    30. printf("open %s ok\n",name);
    31. len = write(fd,msg,strlen(msg));
    32. if(len <= 0){
    33. perror("[[[MAC:112233445566]]]");
    34. close(fd);
    35. exit(-1);
    36. }
    37. printf("write %s ok\n",msg);
    38. while(1){
    39. memset(buf,0,sizeof(buf));
    40. if(fgets(buf,sizeof(buf),p) == NULL)break;
    41. if(strlen(buf) == 0)break;
    42. printf("%s",buf);
    43. }
    44. printf("%d,\n",fclose(p));
    45. printf("%d\n",close(fd));
    46. return 0;
    47. }

    测试略

    二文件描述符转文件流实例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. char *msg = "I'm a student\n";
    9. char buf[100000];
    10. int main(int argc,char *argv[])
    11. {
    12. char *name = "/dev/kmsg";
    13. FILE *p;
    14. int len = 0;
    15. int fd = 0;
    16. fd = open(name,O_RDWR | O_NONBLOCK);
    17. if(fd < 0){
    18. perror("open");
    19. return -1;
    20. }
    21. p = fdopen(fd,"r+");
    22. if(p == NULL){
    23. perror("fdopen");
    24. exit(-1);
    25. }
    26. printf("open %s ok\n",name);
    27. len = write(fd,msg,strlen(msg));
    28. if(len <= 0){
    29. perror("[[[MAC:112233445566]]]");
    30. close(fd);
    31. exit(-1);
    32. }
    33. printf("write %s ok\n",msg);
    34. while(1){
    35. memset(buf,0,sizeof(buf));
    36. if(fgets(buf,sizeof(buf),p) == NULL)break;
    37. if(strlen(buf) == 0)break;
    38. printf("%s",buf);
    39. }
    40. printf("%d,\n",fclose(p));
    41. printf("%d\n",close(fd));
    42. return 0;
    43. }

            输出结果:从最后两行可知,fclose和close无需重复调用。如果重复调用可能会报错,为什么呢,众所周知,文件描述符总是优先利用最小的空闲值,如果当前先调用flose,然后另一个线程使用open又获得了该描述符,这时调用close,就会关闭其他线程刚刚打开的文件。这种BUG,是不是很NICE啊。

    1. $./a.out
    2. 6,1683,68777029537,-;info:/big/csi_driver/css_dma/csi_single.c:css_dev_init:195: order = 8,css_dev->src_buf = 0000000016bad2f8,css_dev->src_addr = bfff8000
    3. 6,1684,68777029538,-;info:/big/csi_driver/css_dma/csi_single.c:css_dev_init:200: order = 8,css_dev->dst_buf = 0000000002aab43a,css_dev->dst_addr = bfff8000
    4. 6,1685,68777029538,-;info:/big/csi_driver/css_dma/csi_single.c:css_init:263: init ok
    5. 0,
    6. -1

    fopen到底是阻塞的还是非阻塞的?

    小结

  • 相关阅读:
    Python学习 day03(注意事项)
    pynvml.nvml.NVMLError_FunctionNotFound: Function Not Found
    视觉语言大模型llava学习
    c++ 学习之运算符重载 之 <<
    C语言二叉树的建立和遍历
    Redis 持久化
    Springboot 拦截器,拦截所有请求,判断是否登录,验证权限
    SpringSecurity 快速入门
    【编程题】【Scratch四级】2020.09 数字之和
    1、3快速格式代码
  • 原文地址:https://blog.csdn.net/yueni_zhao/article/details/127687692