
打开文件
fopen
我们可以使用fopen()创建一个新的或者打开一个文件, 文件信息会保存在一个FILE类型的指针中, 该函数的原型为:
1 | FILE *fopen( const char * filename, const char * mode ); |
filename是文件名, mode是打开模式, 可选值如下:
r- 以只读方式打开一个文件, 该文件必须存在w- 以只写方式打开一个文件, 文件不存在会创建新的文件, 文件存在会首先清空原有内容a- 以追加的方式写文件, 文件不存在会创建新的文件, 文件存在从文件尾开始写文件r+- 以读写方式打开文件, 文件不存在不会创建新的文件w+- 以读写方式打开文件, 文件不存在会创建新的文件, 文件存在会首先清空原有内容a+- 以追加方式读写文件, 文件不存在会创建新的文件, 文件存在从文件尾开始写文件
如果是操作二进制文件, 那么需要在mode里加上b, 如下所示:
1 | "rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b" |
文件成功打开会返回一个’FILE’类型的指针, 如果打开失败, 会返回一个空指针, 并把错误代码存在errno中.
r+ 和 __w+__的区别
看下面的代码
1 |
|
首先运行test, 然后运行test_w, test.txt中的结果如下:
1 | hello |
然后运行test和test_r, test.txt中的结果如下:
1 | hellois a test... |
由上面我们可以看到r+在写时并不清空已有的内容, 但是会从文件开头开始写, 写入的内容会覆盖已有内容.
r, w, a, b, + 的解释
mode一般由上面5个字符组成, 有些可能还会使用t, 下面是该它们的含义
r- read, 读w- write, 写a- append, 追加t- text, 文本文件, 可省略不写b- binary, 二进制文件+- 读和写
新的修饰符 x
在C2011中, 添加一个新的修饰符x, 和w 一起使用, 如下
1 | "wx", "wbx", "w+x" or "w+bx"/"wb+x" |
当文件存在时, x会强制使文件访问出错, 而不是清空文件内容.
关闭文件
我们可以使用fclose来关闭文件, 函数原型为:
1 | int fclose( FILE *fp ); |
如果fclose执行成功, 会返回0, 如果执行出错则会返回EOF(在stdio.h中定义). 当fclose关闭文件时, 会首先将输出流(output) buffer 中的内容写入到文件, 将输入流(input) buffer 中的内容丢弃, 然后关闭文件, 释放其对应的内存.
写文件
在C中有多种方式可以读写文件, 下面将具体介绍它们
fputc
将一个字符写入到fp所指向的输出流中(不只是文件输出流), 写入成功会返回写入的字符, 写入失败会返回EOF, 函数原型为
1 | int fputc( int c, FILE *fp ); |
下面是一个示例:
1 | void test_fputc() { |
test.txt中的内容为
1 | ABCDEFGHIJKLMNOPQRSTUVWXYZ |
另外putchar就是以fputc为基础实现的(额, 这个和实现有关, 这里暂且这么认为)
1 |
putc和fputc的功能一样, 都是将一个字符写入到对应的输出流中, 并且两者的原型是相同的:
1 | extern int fputc(int __c, FILE *__stream); |
但是在实现的时候, putc是以宏定义的方式实现的, 而fputc则是以函数的方式实现的(f表示function)
1 |
关于两者的区别可以参考下面两篇文章
fputc vs putc in C
C语言中fgetc、fputc和getc、putc的区别是什么
大概的意思就是使用putc在一般情况下会快些, 但是可能会出现一些问题, 所以建议使用fputc.
fputs
fputs从指定的地址(str)开始复制, 直到遇到标志结束的null字符\0, 同时\0不会被复制到输出流中. 如果函数执行成功会返回一个非负整数, 否则返回EOF, 该函数的原型为:
1 | int fputs ( const char * str, FILE * stream ); |
下面是一个使用示例
1 | void test_fputs() { |
执行完test_fputs, test.txt中的内容如下所示, 注意c1只写入了ABC
1 | this is a test... |
和fputs相关的一个函数为puts, 其函数原型为:
1 | extern int puts(const char *__str); |
puts不可指定输出流, 默认会输出到标准输出流(stdout), 除此之外puts在输出完内容之后会在内容后面追加上换行符(newline character).
fprintf
fprintf用来将格式化数据输出到输出流, 和printf用法相同, 下面是函数原型
1 | int fprintf ( FILE * stream, const char * format, ... ); |
下面是一个使用示例
1 | void test_fprintf() { |
执行test_fprintf后, test.txt中的内容为:
1 | this is a test... |
关于格式化形式可以参考printf, 或者下面的链接
http://www.cplusplus.com/reference/cstdio/fprintf/
读文件
fgetc
fgetc一次读取一个字符, 同时将文件指针往后移一个字符, 如果读取成功会返回读取的字符, 出现错误会返回EOF. 当读到文件末尾时, 也会返回EOF, 并且在输出流中设置文件结束标志(end-of-file indicator). 下面是该函数的原型:
1 | int fgetc ( FILE * stream ); |
下面是一个使用示例, 其中test.txt中的内容为this is a test...
1 | void test_fgetc() { |
输出结果为:
1 | this is a test...��� |
对应的ascii码值为:
1 | 116 104 105 115 32 105 115 32 97 32 116 101 115 116 46 46 46 -1 -1 -1 |
当读到文件末尾时返回EOF(即-1), 而ascii码中没有-1的对应值, 所以会显示乱码.
和fgetc相关的函数有getchar和getc, 它们的关系和fputc与putchar, putc的关系一样, 下面是getchar和getc的实现
1 |
fgets
该函数的原型为:
1 | char * fgets ( char * str, int num, FILE * stream ); |
fgets从stream中读取内容到str, 当满足下面任意一个条件时完成读取操作:
- 读取了__num-1__个字符
- 读到了换行符(newline character)
- 读到了文件结尾(end-of-file)
注意第二条, 换行符也会被读到str中. 读取完成后会在str后面追加上 终止null字符 (即\0), 这也是第一条为什么只读 num-1 个字符的原因. 函数返回值是一个指向str的指针.
下面是一个使用示例,
1 | void test_fgets() { |
其中test.txt中内容为:
1 | this is a test... |
执行结果为:
1 | c is 'this' |
gets从标准输入流(stdin)里读取数据, 以换行符(回车)作为读取完成的标志, 下面是该函数的原型
1 | char * gets ( char * str ); |
下面是一个使用示例:
1 | void test_gets() { |
在编译时会有警告
1 | file.c:102:5: warning: ‘gets’ is deprecated (declared at /usr/include/stdio.h:638) [-Wdeprecated-declarations] |
即gets函数已过时deprecated, 不建议使用, 而应使用fgets代替
fscanf
fscanf以格式化的形式读入数据, 函数原型如下:
1 | int fscanf ( FILE * stream, const char * format, ... ); |
fscanf以空格和换行符作为读入的结束字符, 同时在fscanf读入时会忽略第一个非空字符前面的空白符(空格,换行,tab), 下面是一个测试示例
1 | void test_scanf() { |
其中test.txt中的内容为:
1 |
|
程序执行结果为:
1 | num[0] is 10 |
在test.txt中 10 前面有个空行, 55 前面有多个空格, 并且后面有 dddd等非数字字符, fscanf在读入时会忽略掉前面的空白符, 并且执行到不匹配的地方就不再往后读入.
参考文章
http://www.tutorialspoint.com/cprogramming/c_file_io.htm
http://www.cplusplus.com/reference/cstdio/
http://www.2cto.com/kf/201207/143344.html
- 本文标题:【C】文件操作
- 创建时间:2015-12-15 19:52:01
- 本文链接:posts/b017.html
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!