学而时习之: C语言中的文件处理

63 阅读9分钟

文件处理在C语言中是指我们对文件进行创建、打开、读取、写入和关闭等操作的过程。C语言提供了不同的函数,如fopen()、fwrite()、fread()、fseek()、fprintf()等,以便在我们的程序中执行输入、输出以及多种不同的C文件操作。

1.打开文件

在C语言中打开文件需使用fopen()函数,并指定文件名(或文件路径)及所需的访问模式。 fopen() 的语法

FILE* fopen(*file_name, *access_mode);
   -  `file_name`:   如果文件与源文件位于同一目录下,则使用文件名。否则,需使用完整路径。
   -  `access_mode`: 指定打开文件所要进行的操作模式
   
   返回值:
    -   如果文件成功打开,则返回一个指向该文件的文件指针。
    -   如果文件未能打开,则返回 NULL

文件打开模式(也称访问模式)用于指定允许对已打开文件执行的操作类型。它们会作为参数传递给 fopen() 函数。一些常用的文件访问模式列举如下:

打开模式描述
r搜索文件。若文件成功打开,fopen() 将其加载到内存,并设置一个指向文件第一个字符的指针。若文件无法打开,fopen() 返回 NULL。
rb二进制模式打开用于读取。如果文件不存在,fopen() 返回 NULL。
w文本模式打开用于写入。如果文件已存在,其内容将被覆盖。如果文件不存在,则创建一个新文件。若无法打开文件则返回 NULL。
wb二进制模式打开用于写入。如果文件已存在,其内容将被覆盖。如果文件不存在,则创建它。
a搜索文件。若文件成功打开,fopen() 将其加载到内存,并设置一个指向文件最后一个字符的指针。它仅以追加模式打开。如果文件不存在,则创建一个新文件。若无法打开文件则返回 NULL。
ab二进制模式打开用于追加。数据被添加到文件末尾。如果文件不存在,则创建它。
r+搜索文件。若文件成功打开,fopen() 将其加载到内存,并设置一个指向文件第一个字符的指针。若无法打开文件则返回 NULL。
rb+二进制模式打开用于读取和写入。如果文件不存在,fopen() 返回 NULL。
w+搜索文件。如果文件已存在,其内容将被覆盖。如果文件不存在,则创建一个新文件。若无法打开文件则返回 NULL。
wb+二进制模式打开用于读取和写入。如果文件已存在,其内容将被覆盖。如果文件不存在,则创建它。
a+搜索文件。若文件成功打开,fopen() 将其加载到内存,并设置一个指向文件最后一个字符的指针。它以读取和追加模式打开文件。如果文件不存在,则创建一个新文件。若无法打开文件则返回 NULL。
ab+二进制模式打开用于读取和追加。如果文件不存在,则创建它。

如上文所述,若需对二进制文件进行操作,则必须在模式末尾附加字母 'b'。例如,应使用 "wb" 替代 "w",使用 "a+b" 替代 "a+"。

创建文件:
fopen() 函数不仅能够打开文件,在文件尚不存在时,它还可以创建文件。为此,我们需要使用那些在文件未找到时允许创建文件的模式,例如 ww+wbwb+aa+ab 以及 ab+

总结一下:

你的需求应使用的正确模式说明
读写一个已有的二进制文件"rb+" 或 "r+b"文件必须存在。
创建并读写一个新的二进制文件"wb+" 或 "w+b"文件不存在则创建,存在则清空其内容。
在二进制文件末尾追加并允许读取"ab+" 或 "a+b"写入总是在末尾,读取可以定位到任何位置。

2.向文件写入数据

文件写入操作可以通过 fprintf() 和 fputs()  函数来实现。C 语言还提供了其他一些可用于向文件写入数据的函数,例如:

函数描述
fprintf()类似于 printf(),该函数使用格式化字符串可变参数列表将输出写入文件。
fputs()将整行字符串写入文件,并在末尾不自动添加换行符。
fputc()向文件写入单个字符
fputw()向文件写入一个整数
fwrite()指定数量的字节写入二进制文件

3.从文件读取数据

在C语言中,文件读取操作可以使用 fscanf() 或 fgets() 函数来执行。这两个函数的功能分别与 scanf() 和 gets() 相同,但多了一个额外的参数__文件指针。此外,我们还可以使用其他一些函数来从文件读取数据,这些函数列出如下:

函数描述
fscanf()使用格式化字符串可变参数列表从文件读取输入。
fgets()从文件中读取整行内容
fgetc()从文件中读取单个字符
fgetw()从文件中读取一个整数
fread()二进制文件中读取指定字节数的数据。

4.关闭文件

fclose() 函数用于关闭文件。在完成成功的文件操作后,必须始终关闭文件以将其从内存中移除。

fclose(file_pointer);

5.移动文件指针

文件指针通常根据打开模式或上一次读/写操作指向相应位置。我们可以使用 fseek() 函数手动将该指针移动到文件中的任意位置。

fseek(fptr, offset, pos);

6.读写二进制文件

二进制文件的操作与文本文件操作类似,但存在一些细微差别。 打开二进制文件,要以二进制模式打开文件,我们需要在 fopen() 函数中使用 rbrb+abab+wb 和 wb+ 等访问模式。同时,我们通常为二进制文件名使用 .bin 扩展名。

fptr = fopen("filename.bin", "rb");
fptr = fopen("filename1.bin", "wb");

6.1 向二进制文件写入数据

我们使用 fwrite() 函数将数据写入二进制文件。数据以比特(0 和 1)的形式写入二进制文件。

fwrite(ptr, size, nmemb, file_pointer);
    -   `ptr`:指向待写入内存块的指针。
    -   `size`:每个要写入元素的大小(以字节为单位)。
    -   `nmemb`:元素的数量。
    -   `file_pointer`:指向输出文件流的 FILE 指针。
    返回值:成功写入的对象数量。

6.2从二进制文件读取数据

在C语言中,可使用 fread() 函数从二进制文件读取数据。数据以其存储形式(即二进制形式)从文件中读取。

fread(ptr, size, nmemb, file_pointer);
    -   `ptr`:指向待读取内存块的指针。
    -   `size`:每个要读取元素的大小(以字节为单位)。
    -   `nmemb`:要读取的元素数量。
    -   `file_pointer`:指向输入文件流的 FILE 指针。
    返回值:成功读取的对象数量。

更多C语言文件操作函数
下表列出了其他一些可用于执行文件操作或辅助执行文件操作的函数。

函数描述
fopen()用于创建文件或打开文件。
fclose()用于关闭文件。
fgets()用于从文件中读取数据。
fprintf()用于将数据块写入文件。
fscanf()用于从文件中读取数据块。
getc()用于从文件中读取单个字符。
putc()用于向文件写入单个字符。
fseek()用于将文件指针的位置设置为指定位置。
ftell()用于返回文件指针的当前位置。
rewind()用于将文件指针设置到文件的开头。
putw()用于向文件写入一个整数。
getw()用于从文件中读取一个整数。

总结更新2025/10/13 C 标准库 <stdio.h> 文件/控制台 IO 接口速查表
(C99 及其后通用,按功能分组)

分类原型作用简述备注
打开关闭FILE *fopen(const char *path, const char *mode);打开文件并返回流指针mode 含 "r"/"w"/"a"/"+"/b
FILE *freopen(const char *path, const char *mode, FILE *stream);重新绑定已有流到新文件常用于重定向
int fclose(FILE *stream);关闭流,刷新缓冲区返回 0 成功,EOF 失败
int fflush(FILE *stream);立即刷新输出缓冲区stream=NULL 刷新全部
二进制读size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);读 nmemb 块,每块 size 字节返回实际读到的块数
二进制写size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);写 nmemb 块返回实际写入块数
字符输入int fgetc(FILE *stream);读一个无符号字符转 int返回 EOF 表示结束/错误
int getc(FILE *stream);同 fgetc,可能为宏实现
int getchar(void);从 stdin 读一个字符等价 getc(stdin)
字符输出int fputc(int c, FILE *stream);写一个字符
int putc(int c, FILE *stream);同 fputc,可能为宏
int putchar(int c);写字符到 stdout等价 putc(c, stdout)
行输入char *fgets(char *s, int size, FILE *stream);读一行(含 '\n')到 s返回 NULL 表示 EOF/错误
char *gets(char *s);弃用,无边界检查C11 已删除
行输出int fputs(const char *s, FILE *stream);写字符串(不含自动 '\n')返回非负成功,EOF 失败
int puts(const char *s);写字符串并自动加 '\n' 到 stdout
格式化输入int fscanf(FILE *stream, const char *fmt, ...);按格式从流读返回成功赋值的项数
int scanf(const char *fmt, ...);从 stdin 读
int sscanf(const char *str, const char *fmt, ...);从字符串读
格式化输出int fprintf(FILE *stream, const char *fmt, ...);按格式写到流返回写入字节数
int printf(const char *fmt, ...);写到 stdout
int sprintf(char *str, const char *fmt, ...);写格式化结果到字符串
int snprintf(char *str, size_t size, const char *fmt, ...);带长度保护版 sprintfC99
定位int fseek(FILE *stream, long offset, int whence);移动读写位置whence=SEEK_SET/SEEK_CUR/SEEK_END
long ftell(FILE *stream);返回当前偏移字节数
void rewind(FILE *stream);回绕到文件头等价 fseek(stream,0,SEEK_SET)
int fgetpos(FILE *stream, fpos_t *pos);保存当前位置到大整数类型
int fsetpos(FILE *stream, const fpos_t *pos);恢复到保存位置
错误/结束int feof(FILE *stream);检测流是否到达文件尾非 0 表示 EOF
int ferror(FILE *stream);检测流是否出错非 0 表示有错误
void clearerr(FILE *stream);清除 EOF 与错误标志
缓冲区设置void setbuf(FILE *stream, char *buf);切换缓冲模式/提供用户缓冲区buf=NULL 则为无缓冲
int setvbuf(FILE *stream, char *buf, int mode, size_t size);精细控制缓冲mode=_IOFBF/_IOLBF/_IONBF
临时文件FILE *tmpfile(void);创建自动删除的二进制临时文件返回打开好的 FILE *
char *tmpnam(char *s);生成唯一临时文件名建议改用 tmpfile
文件描述符桥接int fileno(FILE *stream);返回流对应的底层 fdPOSIX 扩展
FILE *fdopen(int fd, const char *mode);把已有 fd 包装成 FILE *POSIX 扩展

使用提示 :

  1. 凡带 *scanf 家族,格式串错误易造成未定义行为;优先用 fgets+sscanf 组合。
  2. 二进制读写注意平台字节序与结构对齐。
  3. 写后及时 fflushfclose,否则数据可能滞留在用户缓冲区。