linux fopen open


原文链接: linux fopen open

每天进步一点点——Linux中的文件描述符与打开文件之间的关系_linux,文件描述符_Cynric 的博客-CSDN博客

1. 来源

从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别:

  • open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
  • fopen是ANSI C标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。

PS:从来源来看,两者是有千丝万缕的联系的,毕竟C语言的库函数还是需要调用系统API实现的。

2. 移植性

这一点从上面的来源就可以推断出来,fopen是C标准函数,因此拥有良好的移植性;而open是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数CreateFile

3. 适用范围

  • open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
  • fopen是用来操纵普通正规文件(Regular File)的。

4. 文件IO层次

如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。

5. 缓冲

  1. 缓冲文件系统

    缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。

  2. 非缓冲文件系统

    缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。

一句话总结一下,就是open无缓冲,fopen有缓冲。前者与read, write等配合使用, 后者与fread,fwrite等配合使用。

使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:readwrite);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。

这样一总结梳理,相信大家对于两个函数及系列函数有了一个更全面清晰的认识,也应该知道在什么场合下使用什么样的函数更合适,效率更高。

一、open函数

函数原型:int open(const char *path, int access, int mode);
参数解释:
path:要打开的文件路径和名称。
access:访问模式,宏定义和含义如下:
– O_RDONLY(1):只读打开;
– O_WRONLY(2):只写打开;
– O_RDWR(4):读写打开;
还可选择以下模式与以上3种基本模式相与:
– O_CREAT(0x0100)创建一个文件并打开;
– O_TRUNC(0x0200)打开一个已存在的文件并将文件长度设置为0,其他属性保持;
– O_EXCL(0x0400)未使用;
– O_APPEND(0x0800)追加打开文件;
– O_TEXT(0x4000)打开文本文件翻译CR-LF控制字符;
– O_BINARY(0x8000)打开二进制字符,不作CR-LF翻译;
mode:该参数仅在access=O_CREAT方式下使用,其取值如下:
– S_IFMT(0xF000):文件类型掩码;
– S_IFDIR(0x4000):目录;
– S_IFIFO(0x1000):FIFO 专用;
– S_IFCHR(0x2000):字符专用;
– S_IFBLK(0x3000):块专用;
– S_IFREG(0x8000):只为0x0000;
– S_IREAD(0x0100):可读;
– S_IWRITE(0x0080):可写;
– S_IEXEC(0x0040):可执行;
二、fopen函数

函数原型:FILE *fopen(char *filename, char *mode);
参数解释:
– filename:文件名称。
– mode:打开模式:
r:只读方式打开一个文本文件(该文件必须存在);
r+:可读可写方式打开一个文本文件(该文件必须存在);
w:只写方式打开一个文本文件(若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件);
w+:可读可写方式创建一个文本文件(若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件);
a:追加方式打开一个文本文件(若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留));
a+:可读可写追加方式打开一个文本文件(若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留));
rb:只读方式打开一个二进制文件(使用法则同r);
rb+:可读可写方式打开一个二进制文件(使用法则同r+);
wb:只写方式打开一个二进制文件(使用法则同w);
wb+:可读可写方式生成一个二进制文件(使用法则同w+);
ab:追加方式打开一个二进制文件(使用法则同a);
ab+:可读可写方式追加一个二进制文件(使用法则同a+);
返回参数: 文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno 中。一般而言,打开文件后会作一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以在fopen()后请作错误判断及处理。
三、两者的区别

前者属于低级IO,后者是高级IO。
前者返回一个文件描述符,后者返回一个文件指针。
前者无缓冲,后者有缓冲。
前者与 read, write 等配合使用, 后者与 fread, fwrite等配合使用。
后者是在前者的基础上扩充而来的,在大多数情况下,用后者。
————————————————
版权声明:本文为CSDN博主「leon1741」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/LEON1741/article/details/78091974

《Linux系统调用:fileno,fdopen》_yexiangCSDN的专栏-CSDN博客

函数fopen()就是返回打开文件的指针。其实文件描述符和文件指针是可以互相转换的。这要通过fdopen和fileno两个函数实现。它们都包含在头文件stdio.h中。先看fdopen的原型:

FILE * fdopen(int filedes, const char *opentype);
第一个参数filedes是一个打开的文件描述符,opentype是表示打开方式的字符串,和fopen函数具有相同的取值,比如"w"或"w+"等。但是你必须保证该字符串的描述和文件实际的打开方式是匹配的。
文件返回一个新的文件流(stream)的指针。如果操作失败,返回空指针null。

把文件流指针转换成文件描述符用fileno函数,其原型为:

int fileno(FILE *stream);
它返回和stream文件流对应的文件描述符。如果失败,返回-1。
以前知道,当程序执行时,就已经有三个文件流打开了,它们分别是标准输入stdin,标准输出stdout和标准错误输出stderr。和流式文件相对应的是,也有三个文件描述符被预先打开,它们分别是0,1,2,代表标准输入、标准输出和标准错误输出。
需要指出的是,上面的流式文件输入、输出和文件描述符的输入输出方式不能混用,否则会造成混乱。所以上面的函数使用的机会并不多。以后会讲到使用的场合。

相关函数: open, fopen
表头文件:#include
定义函数: int fileno(FILE *stream)
函数说明:fileno()用来取得参数stream指定的文件流所使用的文件描述词
返回值 :返回文件描述词
范例:

#include <stdio.h>
main()
{
    FILE  *fp;
    int  fd;
    fp = fopen("/etc/passwd", "r");
    fd = fileno(fp);
    printf("fd = %d\n", fd);
    fclose(fp);
}

一、介绍
库函数: fileno(),fdopen(). 作用是混合使用库函数和系统函数调用进行文件的I/O操作。 

#include

//将一个文件流中对应打开的文件描述符fd返回
int fileno(FILE *stream);
参数:

stream: fopen之类的函数打开的文件流

返回值:

正确返回文件描述符fd,一般不会错误除非无效的流,返回-1,并设置errno为EBADF

// 给定一个文件描述符和mode创建一个使用该描述符对应的流,与fileno相反
FILE *fdopen(int fd, const char *mode);
参数:

fd: open函数打开的文件描述符
mode: 参考fopen函数的mode

返回值:

正确返回流,错误返回NULL并设置errno  

注意:
1.mode必须是fopen中的mode
2.w”和“w+”不导致文件截断,因为截断是文件打开时的动作,而在此情形下,文件已经被打开。
3.fdopen()建立的新流的文件位置与描述字fd的文件位置相同,且流的错误指示器和文件结束指示器均被清除。
   fdopen()的实质是为已打开的文件描述字提供标准I/O缓冲。
4.fileno()函数返回与流stream相连的文件描述字。利用它可以确定流的底层文件描述字。
    例如,当调用dup()或fcntl()时就需要知道与流相连的文件描述字。

二、实例

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
 
int main(int argc, char *argv[])
{
	int fd;
	int nfd;
	FILE * fp;
	int ret;
	char *filename = "fileno_fdopen.txt";
	FILE *fdopen(int fd, const char *mode);
	int fileno(FILE *stream);
 
	fd = open(filename, O_RDWR|O_CREAT,066);
	if( fd < 0 )
	{
		printf("open %s error! \n",filename);
		return -1;
	}	
 
	printf("fd = %d \n",fd);
 
	errno = 0;
	fp = fdopen(fd,"wr+");
	if(fp ==NULL && errno!=0)
	{
		printf("fdopen error ! \n");
		return -1;
	}
 
	printf("fp = %p errno = %d \n",fp,errno);
 
#if 1
	//库写函数通过流写数据
	ret = fwrite("Hello",1,strlen("Hello"),fp);
	if(ret != strlen("Hello"))
	{
		printf("fwrite error ! \n");
		return -1;
	}
 
	//写完刷新数据
	fflush(fp);
#endif	
	errno = 0;
	// 再把转换的流转为fd
	nfd = fileno(fp);
	if(nfd == -1 && errno!=0)
	{
		printf("fileno error ! \n");
		return -1;
	}
 
	// 对比fd是否一样
	printf("nfd = %d , before fd = %d \n",nfd,fd);
 
	write(nfd,"World\n",strlen("World\n"));
 
	// 系统调用同步
	fsync(nfd);
	
	close(nfd);
	return 0;
}

yexiang@ubuntu:<_IO>$ ./a.out
fd = 3
fp = 0x1793420 errno = 0
nfd = 3 , before fd = 3
yexiang@ubuntu:<_IO>$ sudo cat fileno_fdopen.txt

————————————————
版权声明:本文为CSDN博主「HarkerYX」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yexiangCSDN/article/details/103509439

`