假如,你正在升级一个成熟的项目,其中使用的是文件流,你需要使用文件描述符中的某些功能,或者反过来,这时候,就需要他们之间的互相转换操作。
涉及的头文件和函数
- #include
- #include
- #include
-
- int fileno(FILE* stream);
- FILE* fdopen(int fd,const char *mode);
- FILE *fopen(const char *path, const char *mode);
- 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);
源码:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- char *msg = "I'm a student\n";
- char buf[100000];
- int main(int argc,char *argv[])
- {
- char *name = "/dev/kmsg";
- FILE *p;
- int len = 0;
- int fd = 0;
- int flags;
- p = fopen(name,"r+");
- if(p == NULL){
- perror("open");
- return -1;
- }
- fd = fileno(p);
- if(fd < 0){
- perror("fdopen");
- exit(-1);
- }
-
- flags = fcntl(fd,F_GETFL,0);
- flags |= O_NONBLOCK;
- fcntl(fd,F_SETFL,flags);
- printf("open %s ok\n",name);
- len = write(fd,msg,strlen(msg));
- if(len <= 0){
- perror("[[[MAC:112233445566]]]");
- close(fd);
- exit(-1);
- }
- printf("write %s ok\n",msg);
- while(1){
- memset(buf,0,sizeof(buf));
- if(fgets(buf,sizeof(buf),p) == NULL)break;
- if(strlen(buf) == 0)break;
- printf("%s",buf);
- }
- printf("%d,\n",fclose(p));
- printf("%d\n",close(fd));
- return 0;
- }
测试略
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- char *msg = "I'm a student\n";
- char buf[100000];
- int main(int argc,char *argv[])
- {
- char *name = "/dev/kmsg";
- FILE *p;
- int len = 0;
- int fd = 0;
- fd = open(name,O_RDWR | O_NONBLOCK);
- if(fd < 0){
- perror("open");
- return -1;
- }
- p = fdopen(fd,"r+");
- if(p == NULL){
- perror("fdopen");
- exit(-1);
- }
- printf("open %s ok\n",name);
- len = write(fd,msg,strlen(msg));
- if(len <= 0){
- perror("[[[MAC:112233445566]]]");
- close(fd);
- exit(-1);
- }
- printf("write %s ok\n",msg);
- while(1){
- memset(buf,0,sizeof(buf));
- if(fgets(buf,sizeof(buf),p) == NULL)break;
- if(strlen(buf) == 0)break;
- printf("%s",buf);
- }
- printf("%d,\n",fclose(p));
- printf("%d\n",close(fd));
- return 0;
- }
输出结果:从最后两行可知,fclose和close无需重复调用。如果重复调用可能会报错,为什么呢,众所周知,文件描述符总是优先利用最小的空闲值,如果当前先调用flose,然后另一个线程使用open又获得了该描述符,这时调用close,就会关闭其他线程刚刚打开的文件。这种BUG,是不是很NICE啊。
- $./a.out
- 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
- 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
- 6,1685,68777029538,-;info:/big/csi_driver/css_dma/csi_single.c:css_init:263: init ok
- 0,
- -1