文章目录
这篇文章主要解决如下几个问题:
- C语言中如何进行文件读写?
- fopen时的文本模式和二进制模式有什么区别?
- fread、fgets和fscanf各有什么区别,如何使用?
- fwrite、fputs和fprintf各有什么区别,如何使用?
概述
在C语言中进行文件操作,可以使用C库提供的文件读写库函数。我们经常使用的库函数如下:
FILE *fopen( char *file, char *open_mode ); //打开文件,读文件到内存,返回文件信息结构指针
size_t fread(void *ptr, size_t size, size_t n, FILE *stream)//按字节读取文件内容到s中
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream)//按字节将s地址中的数据写到文件中
char *fgets( char *s, int max_size, FILE * stream); //读一行数据到缓冲区s中
int fputs(const char *str, FILE *stream) ;//将字符串s写入文件
int fscanf(FILE *stream, const char *format, ...) ;//fscanf(文件流指针,格式字符串,输出表列);
int fprintf(FILE *stream, const char *format, ...);//fprintf(文件流指针,格式字符串,输出表列);
int fseek( FILE * stream, long offset, int whence); //移动文件指针到指定位置(0,1,2):SEEK_SET,SEEK_CUR,SEEK_END
void rewind(FILE * stream); //回到文件头
long ftell(FILE * stream); //得到当前文件偏移位置
int feof(FILE *stream);//文件是否结束
fclose(FILE * stream); //关闭文件,刷新缓存到物理磁盘上
针对上述函数,更为详细的描述请大家参考cppreference上的文档描述:https://en.cppreference.com/w/c/io/
常用函数
fopen
用于打开一个文件,用于后续读写。该函数原型如下:
FILE *fopen( const char *filename, const char *mode ); // C99标准
errno_t fopen_s( FILE *restrict *restrict streamptr, const char *restrict filename, const char *restrict mode ); // C11标准
需要注意的是:
- 该函数返回的是一个FILE结构的指针,如果文件打开失败,则该指针返回值为空
- 第一个参数filename为文件名,有相对路径和绝对路径两种传入方式
- 绝对路径:包含完整的路径,如
E:\SRC\FileIO\fgets_fputs\mystr.txt
- 绝对路径:包含完整的路径,如
- 相对路径:以当前exe所在路径为参考的文件路径,如果需要返回上级目录,使用
..
。比如当前exe位于E:\src\Cheese\Debug
目录下,而待读取的hello.txt位于E:\src\Cheese\Cheese\hello.txt
,则使用相对路径为:..\Cheese\hello.txt
。
- 如果直接运行exe,则“当前路径”是以exe所在路径为基准的,如果fopen时直接输入文件名,则意味着对应要打开的文件和exe处于同级目录下。
- 如果通过VS运行exe,则“当前路径”以源码所在的工程路径为基准的,如果fopen时直接输入文件名,则意味着对应要打开的文件位于对应的VS工程目录下。
- 如果路径使用
\
来标识,需要进行转义:\\
- 第二个参数是打开文件时使用的模式,主要有以下六种:
File access mode string |
含义 | 解释 | 文件存在时的操作 | 文件不存在时的操作 |
---|---|---|---|---|
"r" |
read | 打开文件供读取 | 从文件头部开始读取 | 打开失败 |
"w" |
write | 创建文件供写入 | 清空文件原有内容,重新写入 | 创建新文件 |
"a" |
append | 向文件尾部追加新内容 | 向文件尾部追加 | 创建新文件 |
"r+" |
read extended | 打开文件供读取和写入 | 从文件头部开始读取 | 打开失败 |
"w+" |
write extended | 创建文件供读取和写入 | 清空文件原有内容,重新写入 | 创建新文件 |
"a+" |
read extended | 打开文件供读取和写入 | 向文件尾部追加 | 创建新文件 |
- 需要注意的是"a"及"a+"模式下,当文件已存在的情况下,是向文件尾部追加内容,这一点与"w"和"w+"不同。这也是课堂练习题不选第二选项的原因。
- 在一些Windows下C语言的资料中,会提到另一个名为"b"或"t"的后缀,这是所谓的二进制和文本模式。
- 在POSIX标准中(适用于Unix、Linux等环境),文本和二进制模式本身没有差异
- 在Windows环境下,由于所采用的换行符是CRLF(16进制的0x0D 0x0A),出于兼容性考虑,在读写过程中会进行与标准换行符(0x0A)的自动转换。具体说来,在文本模式下,对文件写入时,如果遇到0x0D 0x0A,在写入文件时会被转换成0x0A;而在文件读取时,如果只遇到0x0A,会将其转为0x0D 0x0A。另外,Windows下对于文本模式的文件结尾也有特殊规定,具体可参见MSDN中的论述:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen
In addition to the earlier values, the following characters can be appended to mode to specify the translation mode for newline characters.
In text mode, CTRL+Z is interpreted as an EOF character on input. In files that are opened for reading/writing by using “a+”, fopen checks for a CTRL+Z at the end of the file and removes it, if it’s possible. It’s removed because using fseek and ftell to move within a file that ends with CTRL+Z may cause fseek to behave incorrectly near the end of the file.
In text mode, carriage return-line feed (CRLF) combinations are translated into single line feed (LF) characters on input, and LF characters are translated to CRLF combinations on output. When a Unicode stream-I/O function operates in text mode (the default), the source or destination stream is assumed to be a sequence of multibyte characters. Therefore, the Unicode stream-input functions convert multibyte characters to wide characters (as if by a call to the mbtowc function). For the same reason, the Unicode stream-output functions convert wide characters to multibyte characters (as if by a call to the wctomb function).
- fopen函数返回为FILE对象的指针,如果文件打开失败,则该指针为空指针。因此,严谨的写法应该在函数返回后,对指针值进行判断。
fclose
fclose应与fopen配对使用,关闭一个被fopen打开的文件对象指针。其函数原型如下:
int fclose( FILE *stream );
需要注意的是,如果对文件内容进行了写入或修改,只有当调用fclose之后,才能保证对应的修改一定被同步到了对应文件中。
fgets和fputs
概述
这一组函数用于对字符串的读取和写入。函数原型如下:
int fputs( const char *str, FILE *stream );
char* fgets( char *str, int count, FILE *stream );
- str参数是待写入文件或从文件读出的字符串
- stream是用于传入fopen打开的FILE*指针,指定读写的文件对象。
- fgets中的count用于指定最大可从文件读到内存中的字符串长度(通常被设置为str的最大长度)
文本模式
我们先来看一个简单的例子:
FILE* fp = fopen("mystr.txt"