分享

open与fopen区别

 cgf2057 2011-09-01
open和fopen的区别 (2011-03-07 09:14)
标签二进制  LINUX  linux  style  open  分类: linux编程

open和fopen的区别:

/blog/905406
主要区别是涉及到系统,而不是缓冲。带f的是标准IO,代码可以移植。不带f只能在UNIX/LINUX系统调用。  open一个是整数,fopen一个是指针(FILE *)。  二者区别大致可以总结为以下几点:
1,fread是带缓冲的,read不带缓冲.  
2,fopen是标准c里定义的,open是POSIX中定义的.  
3,fread可以读一个结构.read在linux/unix中读二进制与普通文件没有区别.  
4,fopen不能指定要创建文件的权限.open可以指定权限.  
5,fopen返回指针,open返回文件描述符(整数).  
6,linux/unix中任何设备都是文件,都可以用open,read.
1.非缓冲文件系统
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲 文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于 ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。
open, close, read, write, getc, getchar, putc, putchar 等
2.缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从 内存“缓冲区”依此读入接收的变量。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存 “缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。
fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等

前者属于低级IO,后者是高级IO。
前者返回一个文件描述符(用户程序区的),后者返回一个文件指针。
前者无缓冲,后者有缓冲。
前者与 read, write 等配合使用, 后者与 fread, fwrite等配合使用。
后者是在前者的基础上扩充而来的,在大多数情况下,用后者。
open 是Linux/Unix系统调用 返回的是文件句柄,文件的句柄是文件在文件描述副表里的索引,fopen是C的库函数,返回的是一个指向文件结构的指针。

fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api
linux中的系统函数是open,fopen是其封装函数。
fopen最终还是要调用底层的系统调用open。

以下摘自 /media/ch28s02.html

open、read、write、close等系统函数称为无缓冲I/O(Unbuffered I/O)函数,因为它们位于C标准库的I/O缓冲区的底层[36]。用户程序在读写文件时既可以调用C标准I/O库函数,也可以直接调用底层的Unbuffered I/O函数,那么用哪一组函数好呢?

  • 用Unbuffered I/O函数每次读写都要进内核,调一个系统调用比调一个用户空间的函数要慢很多,所以在用户空间开辟I/O缓冲区还是必要的,用C标准I/O库函数就比较方便,省去了自己管理I/O缓冲区的麻烦。

  • 用C标准I/O库函数要时刻注意I/O缓冲区和实际文件有可能不一致,在必要时需调用fflush(3)。

  • 我们知道UNIX的传统是Everything is a file,I/O函数不仅用于读写常规文件,也用于读写设备,比如终端或网络设备。在读写设备时通常是不希望有缓冲的,例如向代表网络设备的文件写数据就是希望数据通过网络设备发送出去,而不希望只写到缓冲区里就算完事儿了,当网络设备接收到数据时应用程序也希望第一时间被通知到,所以网络编程通常直接调用Unbuffered I/O函数。

C标准库函数是C标准的一部分,而Unbuffered I/O函数是UNIX标准的一部分,在所有支持C语言的平台上应该都可以用C标准库函数(除了有些平台的C编译器没有完全符合C标准之外),而只有在UNIX平台上才能使用Unbuffered I/O函数,所以C标准I/O库函数在头文件stdio.h中声明,而read、write等函数在头文件unistd.h中声明。在支持C语言的非UNIX操作系统上,标准I/O库的底层可能由另外一组系统函数支持,例如Windows系统的底层是Win32 API,其中读写文件的系统函数是ReadFile、WriteFile。

参数fd是要关闭的文件描述符。需要说明的是,当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在终止时内核也会自动关闭它打开的所有文件。但是对于一个长年累月运行的程序(比如网络服务器),打开的文件描述符一定要记得关闭,否则随着打开的文件越来越多,会占用大量文件描述符和系统资源。

由open返回的文件描述符一定是该进程尚未使用的最小描述符。由于程序启动时自动打开文件描述符0、1、2,因此第一次调用open打开文件通常会返回描述符3,再调用open就会返回4。可以利用这一点在标准输入、标准输出或标准错误输出上打开一个新文件,实现重定向的功能。例如,首先调用close关闭文件描述符1,然后调用open打开一个常规文件,则一定会返回文件描述符1,这时候标准输出就不再是终端,而是一个常规文件了,再调用printf就不会打印到屏幕上,而是写到这个文件中了。

以下摘自 /u/21067/showart_213410.html

1、
open 是系统调用 返回的是文件句柄,文件的句柄是文件在文件描述副表里的索引,fopen是C的库函数,返回的是一个指向文件结构的指针。
2、
fopen的实现要调用open, 关键看你想返回什么了, FILE指针还是描述符?
3、
32位环境下,编译加“-D_FILE_OFFSET_BITS=64”
要在open里加O_LARGEFILE标记
[code]
static int ext2_open_file (struct inode * inode, struct file * filp)
{
        if (!(filp->f_flags & O_LARGEFILE) &&
            inode->i_size > 0x7FFFFFFFLL)
                return -EFBIG;
        return 0;
}
[/code]
0x7FFFFFFF就是2G-1。 看一下这个逻辑, 就知道open时必须制定O_LARGEFILE.
4、
fopen一个文件,fclose两次,会是什么样的情况?
本人测试了一下:
在aix,hp,sco,unixware上fclose第一次成功,fclose第二次返回错误
在linux上.fclose第一次成功,第二次报segmentation fault,程序吐核
5、
计算机语言遵循的规范称为标准。C语言有C标准,C++语言有C++标准。标准中详细规定了你能够做什么和不能做什么。标准中规定不能做的就是我说的标准的禁止事项。

其实不只是标准,在介绍学习或使用语言的书中也会出现大量的应该做和不应该做的说明,只是一般不可能象标准那样全面。所以,在“The C Programming Language”中没有提到这个未定义行为也没有什么奇怪的。

"程序员基本职责"?…… 可以认为是为了实现程序预定的目的,对程序员的基本要求。在使用语言上的一个基本要求就是要符合标准规定。

>> 还有一个问题
>> 在非linux系统下,我使用fopen打开的文件
>> 使用close关闭(注意,不是fclose),缓冲也相应关闭;
>> 而在linux系统下,如果使用close关闭,结果缓冲还残留在内存中.
>> 这个是不是说明linux 不支持标准?

如果用 close 来关闭一个缓冲文件,其行为是未定义的。因为 close 并不能保证刷新缓存,所以 fclose != close,不过可以这样认为:fclose = fflush + close。

既然 close 用 fopen 打开的文件是一种未定义行为,就是说标准没有规定这样会导致什么行为,所以结果导致缓冲刷新也罢不刷新也罢,这样的行为都是合法的,编译器可以自由实现。

由于未定义行为是标准规定的禁止在程序中出现的行为,所以一般没有必要再去讨论未定义行为到底有什么、或者有哪些具体的表现。

>> 那我觉得linux下编译的过程中就应该发出警告,fclose两次是未定义的,有潜在危险

想法是不错的。只不过未定义行为不是语法错误,在编译阶段一般是发现不了的,或者实现起来相当困难,只好推移到运行阶段、借助于程序的行为异常来发现这些错误。比如,fclose两次、除数为0、悬挂指针等带来的行为。当然,也可能因在运行时程序表现正常而发现不了这些错误。这就要求我们在写程序的时候就要尽量处理好,不要出现未定义的行为。对于编译器而言呢,我们希望它会以一种尽量“醒目”的方式提示我们,因此编译器在对未定义行为的实现上其实是有自己的考虑的。

>> 具体fclose两次是未定义的,这个是posix标准还是ansc  c标准呢?

从 man fclose 中可以看出,这是一个ansc  c标准规定的函数。这就意味着它又是一个 posix 标准的函数。posix就是在 ANSI C (C89)基础上实现的,包括了 ANSI C 的全部规定。

>> 但是我觉得一个标准是符合人们的习惯的,那就是如果我去调用一个库函数,
那么这个库函数只有一个出口就是返回值,而现在又出现另外的出口:SEGV信号

1. void函数没有返回值。2. 除了函数的返回值之外函数的参数也可以作为出口。

运行时出现了SEGV说明程序中存在错误。其根本原因在于程序员在程序中使用了未定义行为从而违反了标准所致。
6、
值得一提大家经常可能会遇到的就是strcpy这个函数,如果参数中有NULL值,
例如:strcpy(NULL,"aa")
很快就引起一个段错误.

现在软件要求的不仅仅是效率,那么对于这种情况我们该如何避免这种错误呢?
更多情况下我们使用变量copy,如strcpy(char *str1,char *str2);
为了避免错误,我们可能会在每次copy前判断
if(str1!=NULL)
    strcpy(str1,str2);
我并不觉得这样很麻烦,但是我们万一有个疏忽,某次忘记了
不就造成大错了吗?

解决办法是我们要在原来c库的基础上进行我们的包装
写一个自己的类库,例如改装成
my_safe_strcpy(char *,char *);
但是这样的做法好象不太多见,大家都是直接使用c的库就OK;
7、
int setvbuf(FILE *stream, char *buf, int mode , size_t size);
把缓冲区与流相联,通过改变buf的大小,的确能改变fopen打开的流按系统默认buffer输出。
8、
前者属于低级IO,后者是高级IO。
前者返回一个文件描述符,后者返回一个文件指针。
前者无缓冲,后者有缓冲。
前者与 read, write 等配合使用, 后者与 fread, fwrite等配合使用。
后者是在前者的基础上扩充而来的,在大多数情况下,用后者。
9、
好象是fopen返回给fp的值有问题 因为这个所以导致fclose的时候coredump

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 全屏 打印 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多