标准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+b或wb+
打开可读写文件,若文件存在则文件长度清为零,即会擦写文件
以前内容。若文件不存在则建立该文件
a或ab
以附加的方式打开只写文件。若文件不存在,则会建立该文件,
如果文件存在,写入的数据会被加到文件尾,即文件原先的内容
会被保留
a+或a+b或ab+
以附加方式打开可读写的文件。若文件不存在,则会建立该文
件,如果文件存在,写入的数据会被加到文件尾后,即文件原先
的内容会被保留
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-D或Ctrl-Z。操作系统和标准输入输出库安排你的程序接收EOF值。(然而请注意,这一路有好几个转换。通常情况下,你不能自己检查Ctrl-D或Ctrl-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 函数无关紧要。