当前位置: 首页 > news >正文

【C语言】文件操作全解析

文章目录

    • 一、为什么需要文件操作?
    • 二、认识文件:不止是磁盘上的存储
      • 2.1 程序文件
      • 2.2 数据文件
      • 2.3 文件名的构成
    • 三、文本文件与二进制文件:数据的两种形态
      • 3.1 存储方式差异
      • 3.2 实例对比:整数10000的存储
      • 3.3 二进制文件操作示例
    • 四、文件的打开与关闭:操作的开始与结束
      • 4.1 流的概念
      • 4.2 文件指针
      • 4.3 打开与关闭函数
      • 4.4 文件打开模式
      • 4.5 示例代码
    • 五、文件的顺序读写:按部就班的数据处理
      • 5.1 常用顺序读写函数
      • 5.2 函数对比
    • 六、文件的随机读写:自由定位数据位置
      • 6.1 fseek函数:定位文件指针
      • 6.2 ftell函数:获取当前位置偏移量
      • 6.3 rewind函数:重置文件指针
    • 七、文件读取结束的判定:正确识别结束条件
      • 7.1 feof函数的正确用法
      • 7.2 正确的判断方式
    • 八、文件缓冲区:提升效率的中间层
      • 8.1 缓冲区演示
      • 8.2 重要结论
    • 总结

在C语言编程中,文件操作是实现数据持久化存储的关键技术。无论是保存用户数据、配置信息还是处理大量数据,都离不开文件操作。本文将详细讲解C语言文件操作的方方面面,从基本概念到实际应用,帮助你全面掌握这一重要技能。

一、为什么需要文件操作?

在程序运行过程中,我们处理的数据通常存储在内存中。然而,内存具有临时性的特点——当程序退出或计算机断电时,内存中的数据会全部丢失。如果我们希望数据能够长期保存,以便下次运行程序时继续使用,就必须使用文件将数据存储到磁盘等外部存储设备中。

简单来说,文件操作让程序的数据拥有了"记忆"能力,是实现数据持久化的核心手段。

二、认识文件:不止是磁盘上的存储

在C语言中,我们通常从功能角度将文件分为两类:

2.1 程序文件

程序文件是用于构成程序本身的文件,包括:

  • 源程序文件(.c后缀)
  • 目标文件(Windows环境下为.obj后缀)
  • 可执行程序(Windows环境下为.exe后缀)

2.2 数据文件

数据文件是程序运行时读写的数据载体,比如:

  • 程序需要读取的配置文件
  • 程序输出的日志文件
  • 存储用户信息的数据库文件

本文重点讨论的是数据文件的操作。

2.3 文件名的构成

一个完整的文件名包含三个部分:

  • 文件路径:指示文件在磁盘中的位置
  • 文件名主干:文件的核心标识
  • 文件后缀:指示文件类型

例如:c:\code\test.txt中,c:\code\是路径,test是文件名主干,.txt是后缀。

三、文本文件与二进制文件:数据的两种形态

根据数据的存储形式,数据文件可分为文本文件和二进制文件,它们的区别如下:

3.1 存储方式差异

  • 二进制文件:数据在内存中以二进制形式存储,不加转换直接输出到外存
  • 文本文件:数据在存储前被转换为ASCII码形式,以字符形式存储

3.2 实例对比:整数10000的存储

以整数10000为例:

  • 文本文件存储:占用5个字节(每个字符一个字节),存储内容是’1’,‘0’,‘0’,‘0’,'0’的ASCII码
  • 二进制文件存储:在VS2019环境下仅占用4个字节,直接存储其二进制形式00000000 00000000 00100111 00010000

3.3 二进制文件操作示例

#include <stdio.h>
int main()
{int a = 10000;FILE* pf = fopen("test.txt", "wb");  // 以二进制写入模式打开文件fwrite(&a, 4, 1, pf);  // 将a以二进制形式写入文件fclose(pf);pf = NULL;return 0;
}

在VS中查看二进制文件时,需要使用二进制编辑器,10000会显示为10270000

四、文件的打开与关闭:操作的开始与结束

4.1 流的概念

C语言通过"流"(stream)来操作各种外部设备(包括文件)。流可以想象成"流淌着字符的河",程序通过流与外部设备进行数据交换。

C程序启动时会默认打开3个标准流:

  • stdin:标准输入流(通常对应键盘)
  • stdout:标准输出流(通常对应显示器)
  • stderr:标准错误流(通常对应显示器)

这就是为什么我们可以直接使用scanfprintf函数进行输入输出,而无需手动打开流。

4.2 文件指针

缓冲文件系统中,通过文件指针(FILE*类型)来管理文件。每个被打开的文件在内存中都有一个对应的文件信息区(结构体),存储文件名、状态、当前位置等信息,文件指针就指向这个结构体。

定义文件指针的方式:

FILE* pf;  // 声明一个文件指针变量

4.3 打开与关闭函数

  • 打开文件:使用fopen函数

    FILE * fopen ( const char * filename, const char * mode );
    
  • 关闭文件:使用fclose函数

    int fclose ( FILE * stream );
    

4.4 文件打开模式

文件打开模式决定了对文件的操作权限,常见模式如下:

文件使用方式含义如果指定文件不存在
“r”(只读)打开文本文件用于输入出错
“w”(只写)打开文本文件用于输出创建新文件
“a”(追加)向文本文件末尾添加数据创建新文件
“rb”(只读)打开二进制文件用于输入出错
“wb”(只写)打开二进制文件用于输出创建新文件
“ab”(追加)向二进制文件末尾添加数据创建新文件
“r+”(读写)打开文本文件用于读写出错
“w+”(读写)创建文本文件用于读写创建新文件
“a+”(读写)打开文本文件用于读写,从末尾开始创建新文件

4.5 示例代码

#include <stdio.h>
int main ()
{FILE * pFile;// 打开文件pFile = fopen ("myfile.txt","w");// 文件操作if (pFile!=NULL){fputs ("fopen example",pFile);// 关闭文件fclose (pFile);}return 0;
}

五、文件的顺序读写:按部就班的数据处理

顺序读写是指从文件的开头到结尾依次进行读写操作,C语言提供了一系列函数实现这一功能:

5.1 常用顺序读写函数

函数名功能适用于
fgetc字符输入函数所有输入流
fputc字符输出函数所有输出流
fgets文本行输入函数所有输入流
fputs文本行输出函数所有输出流
fscanf格式化输入函数所有输入流
fprintf格式化输出函数所有输出流
fread二进制输入文件
fwrite二进制输出文件

5.2 函数对比

  • 输入函数家族

    • scanf:从标准输入流读取格式化数据
    • fscanf:从指定输入流读取格式化数据
    • sscanf:从字符串读取格式化数据
  • 输出函数家族

    • printf:向标准输出流输出格式化数据
    • fprintf:向指定输出流输出格式化数据
    • sprintf:将格式化数据输出到字符串

六、文件的随机读写:自由定位数据位置

随机读写允许程序直接定位到文件的任意位置进行操作,主要通过以下函数实现:

6.1 fseek函数:定位文件指针

根据文件指针的当前位置和偏移量来定位指针:

int fseek ( FILE * stream, long int offset, int origin );

参数origin可以是:

  • SEEK_SET:从文件开头开始计算
  • SEEK_CUR:从当前位置开始计算
  • SEEK_END:从文件末尾开始计算

示例:

#include <stdio.h>
int main ()
{FILE * pFile;pFile = fopen ( "example.txt" , "wb" );fputs ( "This is an apple." , pFile );fseek ( pFile , 9 , SEEK_SET );  // 定位到第10个字符位置fputs ( " sam" , pFile );  // 从该位置开始写入fclose ( pFile );return 0;
}
// 最终文件内容为:"This is a sample."

6.2 ftell函数:获取当前位置偏移量

返回文件指针相对于文件起始位置的偏移量:

long int ftell ( FILE * stream );

示例:计算文件大小

#include <stdio.h>
int main ()
{FILE * pFile;long size;pFile = fopen ("myfile.txt","rb");if (pFile==NULL) perror ("Error opening file");else{fseek (pFile, 0, SEEK_END);  // 定位到文件末尾size=ftell (pFile);  // 获取偏移量,即文件大小fclose (pFile);printf ("Size of myfile.txt: %ld bytes.\n",size);}return 0;
}

6.3 rewind函数:重置文件指针

将文件指针重新定位到文件开头:

void rewind ( FILE * stream );

示例:

#include <stdio.h>
int main ()
{int n;FILE * pFile;char buffer [27];pFile = fopen ("myfile.txt","w+");for ( n='A' ; n<='Z' ; n++)fputc ( n, pFile);rewind (pFile);  // 回到文件开头fread (buffer,1,26,pFile);fclose (pFile);buffer[26]='\0';printf(buffer);  // 输出ABCDEFGHIJKLMNOPQRSTUVWXYZreturn 0;
}

七、文件读取结束的判定:正确识别结束条件

很多初学者会错误地使用feof函数来判断文件是否结束,这是需要避免的。

7.1 feof函数的正确用法

feof函数的作用是:当文件读取结束时,判断结束的原因是否是"遇到文件尾"。它并不能直接用来判断文件是否结束。

7.2 正确的判断方式

  1. 文本文件

    • 使用fgetc时,判断返回值是否为EOF
    • 使用fgets时,判断返回值是否为NULL

    示例:

    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {int c;  // 注意:必须是int类型,以处理EOFFILE* fp = fopen("test.txt", "r");if(!fp) {perror("File opening failed");return EXIT_FAILURE;}// fgetc读取失败或遇到文件结束时返回EOFwhile ((c = fgetc(fp)) != EOF)putchar(c);// 判断结束原因if (ferror(fp))puts("I/O error when reading");else if (feof(fp))puts("End of file reached successfully");fclose(fp);
    }
    
  2. 二进制文件

    • 使用fread时,判断返回值是否小于实际要读取的个数

    示例:

    #include <stdio.h>
    enum { SIZE = 5 };
    int main(void)
    {double a[SIZE] = {1.,2.,3.,4.,5.};FILE *fp = fopen("test.bin", "wb");  // 二进制模式fwrite(a, sizeof *a, SIZE, fp);  // 写入数组fclose(fp);double b[SIZE];fp = fopen("test.bin","rb");size_t ret_code = fread(b, sizeof *b, SIZE, fp);  // 读取数组if(ret_code == SIZE) {puts("Array read successfully, contents: ");for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);putchar('\n');} else {  // 错误处理if (feof(fp))printf("Error reading test.bin: unexpected end of file\n");else if (ferror(fp)) {perror("Error reading test.bin");}}fclose(fp);
    }
    

八、文件缓冲区:提升效率的中间层

ANSI C标准采用"缓冲文件系统",系统会自动为每个正在使用的文件在内存中开辟一块"文件缓冲区":

  • 输出数据时:先送到内存缓冲区,缓冲区满后再一起写入磁盘
  • 输入数据时:先从磁盘读取到缓冲区,再从缓冲区送到程序数据区

缓冲区的大小由C编译系统决定。

8.1 缓冲区演示

#include <stdio.h>
#include <windows.h>  // VS2019 WIN11环境
int main()
{FILE* pf = fopen("test.txt", "w");fputs("abcdef", pf);  // 数据先存入输出缓冲区printf("睡眠10秒-此时打开test.txt,文件无内容\n");Sleep(10000);printf("刷新缓冲区\n");fflush(pf);  // 手动刷新缓冲区,数据写入磁盘printf("再睡眠10秒-此时打开test.txt,文件有内容\n");Sleep(10000);fclose(pf);  // 关闭文件时也会刷新缓冲区pf = NULL;return 0;
}

8.2 重要结论

由于缓冲区的存在,操作文件时必须注意:

  • 及时刷新缓冲区(使用fflush函数)
  • 操作结束后关闭文件(fclose会自动刷新缓冲区)

否则可能导致数据未能正确写入文件,造成数据丢失或不一致。

总结

文件操作是C语言编程中的重要技能,掌握它可以让你的程序具备数据持久化能力。本文介绍了文件的基本概念、类型划分、打开关闭、顺序读写、随机读写、结束判定以及缓冲区机制等内容。

在实际编程中,要注意以下几点:

  • 始终检查文件是否成功打开
  • 操作完成后及时关闭文件
  • 正确判断文件读取结束的条件
  • 理解并合理利用缓冲区机制
http://www.dtcms.com/a/318730.html

相关文章:

  • 【感知机】感知机(perceptron)模型与几何解释
  • 第14届蓝桥杯Scratch_选拔赛_初级及中级(STEMA)真题2022年12月18日
  • 深度学习之pytorch安装与tensor(张量)
  • 美式期权定价模型之Barone-Adesi-Whaley定价模型
  • Linux 防火墙(firewalld)详解与配置
  • 第14届蓝桥杯Scratch选拔赛初级及中级(STEMA)真题2022年10月30日
  • Linux中firewalld(防火墙)配置与管理指南
  • 【golang】基于redis zset实现并行流量控制(计数锁)
  • InfluxDB 集群部署与高可用方案(一)
  • C基础 15_day
  • 从代码学习LLM - llama3 PyTorch版
  • css优化、提升性能方法都有哪些?
  • Nacos机制
  • 【图像处理基石】什么是数字高程模型?如何使用数字高程模型?
  • 进阶向:AI聊天机器人(NLP+DeepSeek API)
  • 双馈和永磁风机构网型跟网型联合一次调频并入同步机电网,参与系统一次调频,虚拟惯量下垂,虚拟同步机VSG控制matlab/simulink
  • 202506 电子学会青少年等级考试机器人六级实际操作真题
  • PCB工艺-四层板制作流程(简单了解下)
  • 小实验--继电器定时开闭
  • TrustZone技术详解————这篇是AI写的包括图
  • 贝叶斯算法中的参数调优
  • RK3568下用 Qt Charts 实现曲线数据展示
  • python---getsizeof和asizeof的区别
  • 17.Linux :selinux
  • LMS/NLMS最小均值算法:双麦克风降噪
  • CentOS8.5安装19c单机告警及处理
  • 碳纳米管的原子精度制造——展望
  • 福彩双色球第2025090期篮球号码分析
  • docker启动出现Error response from daemon: Container的问题【已解决】
  • 容器化运维工具(2)Kubernetes 详细教程(含图解)