标准IO

标准IO

ANSIC 指定的标准,这一组API【一组函数】的参数返回值类型

可以在多个平台上运行,包括linux windows

 

标准IO和文件IO比较如下:

 

如果查看某个文件需要哪些头文件,直接man 3 函数名)查看。想成为一个Linux高手应该学会使用man 手册查看全部函数的使用!


FILE*fopen(const char *path, const char *mode);

FILE *fdopen(intfd, const char *mode);

FILE*freopen(const char *path, const char *mode, FILE *stream);

用于将一个打开的流重新定向,

比如stdout[对应显示屏],可以重定向到path 对应的文件中,

如果path不存在,会创建这个文件


FILE*fopen(const char *path, const char *mode); open(char*path , )


功能

打开一个文件

fopen()没有设定创建文件权限的参数,

POSIX.1要求具有如下权限(0666或者-rw-rw-rw)

S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH

S_IRUSR:用户读权限

S_IWUSR:用户写权限

S_IRGRP:用户组读权限

S_IWGRP:用户组写权限

S_IROTH:其他组都权限

S_IWOTH:其他组写权限


用户可以通过umask修改文件存取的权限,其结果为(0666 & umask)共同影响

 

参数

const char *path文件名+路径

const char *mode模式


r rb 打开只读文件,该文件必须存在。(加b的意思是使用二进制文件格式,另一种是文本文件)


w wb 打开只写文件,若文件存在则文件长度清为0,即会擦写文件以

前内容。若文件不存在则建立该文件


w+w+bwb+

打开可读写文件,若文件存在则文件长度清为零,即会擦写文件

以前内容。若文件不存在则建立该文件


aab

以附加的方式打开只写文件。若文件不存在,则会建立该文件,

如果文件存在,写入的数据会被加到文件尾,即文件原先的内容

会被保留


a+a+bab+

附加方式打开可读写的文件。若文件不存在,则会建立该文

件,如果文件存在,写入的数据会被加到文件尾后,即文件原先

的内容会被保留

 


int fclose(FILE*stream) close(fd)


调用成功返回0,失败返回EOF,并设置errno

EOF 的值通常为 -1

在该文件被关闭之前,刷新缓存中的数据。如果标准I / O库已经为该流自动分配了一个缓存,则释放此缓存。

当一个进程正常终止(直接调用exit函数,或从main函数返回),则所有带未写缓存数据的标准I / O流都被刷新,所有打开的标准I / O流都被关闭

 

不要重复关闭某个文件

 

 


int fgetc(FILE*stream);

char *fgets(char*s, int size, FILE *stream);

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);


注意:fgetc 返回值int不是char


char *fgets(char*s, int size, FILE *stream);


功能:

从流中获得字符串到 s

最多读取 size或者遇到换行符也停止

参数

char *s

int size 缓冲区大小

FILE *stream

返回值

若成功则为buf,若已处文件尾端或出错则为null


int fputs(const char *s, FILE *stream);


返回:

若成功则为非负值,若出错则为EOF

函数fputs()将一个以null符终止的字符串写到指定的流,终止符null不写出。

fputs 只负责送到缓冲区,不会补换行符。

如果\0之前的字符串没有换行符,只会送到缓冲区,不会刷新缓冲区。

如果总是使用fgets()fputs(),那么就会熟知在每行终止处我们必须自己加一个新行符


现象先打印12345 输出是行缓冲,因为缓冲区中12345后面是\n,所以会刷新缓冲区

10秒后打印789 因为789后没有换行符,10秒后进程退出,进程刷新缓冲区,结果才会输出

 


size_tfread(void *ptr, size_t size, size_t nmemb, FILE *stream);


size_tfwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);


功能

向流stream 读出/写入zise大小的数据块

内存中数据是什么样,就原样保存到文件中

参数

const void *ptr 要写入的数据的内存的地址

size_t size 数据块大小

size_t nmemb 数据块的个数

FILE *stream

返回值:

读或写的对象数


对于二进制数据我们更愿意一次读或写整个结构

为什么要引入fread/fwrite

1. fgtec 一次只读取一个字符,而我们保存的数据比较复杂,类型丰富【浮点、字符、字符串、整型值】

2. fgets 遇到换行符就停止了,二进制数,非常有可能有的数据内存如果转换成asc形式观察,就很有可能是空字符或者是换行符:如下

int a =0x000a

 


int fseek(FILE *stream, longoffset, int whence);

 

long ftell(FILE *stream);

 

void rewind(FILE *stream);


 

fseek 调用成功返回0,失败返回-1,并设置errno

ftell()用于取得当前的文件位置,调用成功则为当前文件位置指示,若出错则为-1L

rewind()用于设定流的文件位置指示为文件开始,该函数调用成功无返回值。

rewind()等价于(void)fseek(stream, 0L, SEEK_SET)

 


常见问题:


1 为什么大家都说不要使用gets()

 

fgets() 不同, gets() 不能被告知输入缓冲区的大小, 因此不能避免缓冲区的溢出。标准库的 fgets() 函数对 gets() 作了很大的改进, 尽管它仍然不完善。如果真的可能输入很长的行, 还是需要仔细思考, 正确处理


2 我有个读取直到EOF(-1) 的简单程序, 但是我如何才能在键盘上输入那个“EOF” 呢?

 

考虑一下就知道,你输入的绝不能是-1,因为-1是两个字符,而getchar每次读入一个字符。事实上,在你的C程序中看到的EOF值和你在键盘上发出文件结束符的按键组合之间并没有什么关系。EOF不过是向程序发出的一个信号,指明输入不再有任何字符了,不论什么原因(磁盘文件结束、用户结束输入、网络流关闭和I/O错误等。)根据你的操作系统,你可能使用不同的按键组合来表示文件结束,通常是Ctrl-DCtrl-Z。操作系统和标准输入输出库安排你的程序接收EOF值。(然而请注意,这一路有好几个转换。通常情况下,你不能自己检查Ctrl-DCtrl-Z值,你在stdio.h文件中也不会发现EOF宏定义成了这样的值。)

 


3 fopen() 不让我打开文件: "$HOME/.profile" "˜/ .myrcfile“

 

至少在 Unix 系统下, $HOME 这样的环境变量和家目录的表示符 ~ 是由 shell 来展开的。不存在一个调用 fopen() 时的自动扩展机制。

 

 


4 怎样在文件中插入或删除一行(或记录)

 

如果你不能重写文件, 你大概做不了。通常的做法就是重写文件。也许你可以用简单的标志记录删除来取代真的删除, 这样可以避免重写。另外一个可能性, 是使用数据库来取代平坦文件

 


5 这样的代码有什么问题?

char c;

while((c =getchar()) != EOF)

{ /* dosomething */ }

 

第一, 保存getchar 的返回值的变量必须是 int getchar() 可能返回任何字符值, 包括 EOF。如果把 getchar 的返回值截为 char , 则正常的字符可能会被错误的解释为 EOF, 或者 EOF 可能会被修改 (尤其是 char 型为无符号的时候), 从而永不出现


6 怎样在程序里把stdin stdout 重定向到文件?

freopen


7 怎样正确的读取二进制文件?我有时看到0x0a 0x0d 混淆了而且如果数据中包含0x1a (-)的话, 我好像会提前遇到EOF

 

读取二进制数据文件的时候你应该用 ``rb" 调用 fopen(), 确保不会发生文本文件的解释。类似的, 写二进制文件时, 使用 ``wb"

注意文本/二进制区别只是发生在文件打开时: 一旦文件打开之后, 在其上调用何种 I/O 函数无关紧要。

 

 


阅读更多
个人分类: I/O
上一篇文件IO
下一篇输入缓冲区与输出缓冲区
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭