C语言文件操作详解:从打开到读写与结束判定

叶初
叶初
发布时间:2026-10-16 | 4人浏览过
原创

C语言中实现数据持久化主要依赖磁盘文件。本文系统讲解文件类型、文件指针FILE的结构意义,以及fopen/fclose的基础用法。深入解析顺序读写函数(字符、字符串、格式化及二进制流)与随机定位函数(fseek、ftell、rewind),并纠正feof在判断文件结束时的常见误区,提供完整的代码示例。

为什么使用文件

程序运行时的数据通常存储在内存中,断电或程序退出后数据即消失。为了实现数据的持久化,我们需要将数据存储到磁盘文件中或通过数据库保存。使用文件可以将数据直接存放在硬盘上,确保数据在关闭程序后依然存在,直到被显式删除。

什么是文件

在程序设计领域,“文件”的概念分为两类:

  • 程序文件:包括源程序文件(后缀为.c)、目标文件(Windows环境下后缀为.obj)和可执行程序(Windows环境下后缀为.exe)。
  • 数据文件:文件的内容不一定是程序代码,而是程序运行时读写的数据,例如需要从中读取输入数据的文件,或者程序输出结果的文件。

每个文件必须有一个唯一的标识供用户识别,文件名由路径、文件主干名和后缀组成,例如:c:\cyuyan\test.txt。

文件指针

每一个被使用的文件在内存中都会开辟一个相应的文件信息区,用于存放文件的相关信息(如文件名、文件状态及当前读写位置等)。这些信息保存在一个名为 FILE 的结构体变量中。该结构体由系统声明,不同编译器的具体成员可能略有差异,但功能相似。

struct _iobuf {
    char *_ptr;
    int  _cnt;
    char *_base;
    int  _flag;
    int  _file;
    int  _charbuf;
    int  _bufsiz;
    char *_tmpfname;
   };
typedef struct _iobuf FILE;

为了操作文件,我们需要定义一个指向 FILE 类型的指针变量:

FILE* pf; // 文件指针变量

pf 指向某个文件的文件信息区,通过该指针即可访问关联的文件。

文件的打开和关闭

在使用文件前必须先打开它,打开时会返回一个 FILE* 指针,建立指针与文件的关系;使用完毕后必须关闭文件,以防止数据丢失或资源泄露。

第1步:打开文件

入口函数为 fopen,其原型如下:

FILE *fopen( const char *filename, const char *mode );
// filename - 要打开的文件名
// mode     - 文件访问模式

常见的文件访问模式包括读、写、追加及其对应的文本/二进制变体。具体模式含义可参考下表:

第2步:使用与关闭文件

文件操作完成后,使用 fclose 关闭文件:

int fclose( FILE *stream );

以下是一个标准的文件打开、检查与关闭流程示例:

#include<stdio.h>
#include<errno.h>

int main()
{
	// 1. 以写入模式打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0; // 注意:实际工程中应返回适当错误码
	}
	
	// 2. 在此处进行文件读写操作
	// ...
	
	// 3. 关闭文件并将指针置空
	fclose(pf);
	pf = NULL;
	return 0;
}

文件的顺序读写

顺序读写指按照文件内容的先后顺序依次读取或写入。根据数据类型和格式的不同,C语言提供了多组函数:

字符读写

  • fgetc(FILE *stream):从流中读取一个字符。
  • fputc(int c, FILE *stream):将字符写入流。

字符串读写

  • fgets(char *string, int n, FILE *stream):从流中获取一个字符串,最多读取 n-1 个字符。
  • fputs(const char *string, FILE *stream):将字符串写入流。

格式化读写

  • fscanf(FILE *stream, const char *format, ...):从流中读取格式化数据。
  • fprintf(FILE *stream, const char *format, ...):将格式化数据写入流。

二进制读写

  • fread(void *buffer, size_t size, size_t count, FILE *stream):从文件中读取二进制数据块。
  • fwrite(const void *buffer, size_t size, size_t count, FILE *stream):向流中写入二进制数据块。

需要注意的是,scanf/printf 仅针对标准输入/输出流 stdin/stdout,而 fscanf/fprintf 可以指定任意文件流。此外还有针对字符串的 sscanf/sprintf 用于内存中的格式化转换。

文件的随机读写

除了按顺序读写,C语言支持随机访问文件内部任意位置,主要通过以下三个函数实现:

第一步:定位文件指针 fseek

fseek 根据偏移量和起始位置移动文件指针:

int fseek( FILE *stream, long offset, int origin );
// stream  - 文件指针
// offset  - 起始字节数(偏移量)
// origin  - 起始位置(如 SEEK_SET, SEEK_CUR, SEEK_END)

第二步:获取当前位置 ftell

ftell 返回文件指针相对于起始位置的偏移量,可用于确定文件大小:

long ftell( FILE *stream );

第三步:重置指针 rewind

rewind 让文件指针回到文件的起始位置:

void rewind( FILE *stream );

文件结束判定

许多初学者误以为 feof 可以直接用来判断循环条件来读取文件,这是错误的。feof 应用于文件读取结束后,判断是导致结束的原因是“遇到文件尾”还是“读取失败”。

正确的判断方法应根据文件类型区别对待:

  1. 文本文件:判断返回值是否为结束标志。
    • 使用 fgetc 时,判断返回值是否为 EOF。
    • 使用 fgets 时,判断返回值是否为 NULL。
  2. 二进制文件:判断实际读取的项目数是否小于预期数量。
    • 使用 fread 时,判断返回值是否小于 count。

文本文件读取结束的判断示例如图:

二进制文件读取结束的判断示例如图:

以上就是C语言文件操作的详细内容,更多关于C语言编程技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表