C语言文件操作

1、为什么使用文件

2、什么是文件

3、二进制文件和文本文件

4、文件的打开和关闭

5、文件的顺序

6、文件的随机读写

7、文件读取结束的判定

8、文件缓冲区

int main()

{

int a = 0;

scanf("%d", &a); // 这个就是将输入的数字放入文件中

printf("%d\n", a);

return 0;

}

一、问什么使用文件

  • 内存数据断电丢失,文件可永久保存数据
  • 方便数据重复读取、批量处理;
  • 实现多程序数据共享。

二、什么是文件

磁盘(硬盘)上的文件是文件,但是在程序设计中,我们一般谈到的文件有两种:程序文件、数据文件

程序文件:

源程序文件(.c

  • 后缀:.c

    目标文件(.obj / .o

  • 后缀:Windows 下.obj,Linux 下.o

    可执行文件(.exe

  • 后缀:Windows 系统下 .exe

数据文件

专门用来存放程序运行所需数据的文件,不包含代码指令。作用:给程序提供输入数据、保存程序运行结果,实现数据长久存储。

本章讨论的是数据文件

在以前各章所处理数据的输入和输出都是以终端为对象的,即从终端的键盘输入数据并行结果显示在显示器上,其实有的时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读到内存中,使用这里处理的就是磁盘上的文件。

文件名:

一个文件要有一个唯一的文件标识,以便用户识别和引用。文件名包含三个部分,**文件路径 + 文件名主干 + 文件后缀(扩展名);例如:**E:\project\main.c为了方便起见,文件标识常被称为文件名。

二进制文件和文本文件

文本文件(ASCII 文件)

1. 存储规则

每一个字符 按它对应的 ASCII 码 存储,内容就是我们能看懂的文字、数字、符号。

2. 特点

  1. 可用记事本、写字板直接打开阅读、编辑;
  2. \nEOF(-1) 作为结束标志;
  3. 占用空间略大,读写速度稍慢;
  4. 适合存放文字、普通数据。

二进制文件

1. 存储规则

数据直接按照内存中的二进制原样保存,不转换成 ASCII 字符。

2. 特点

  1. 记事本打开显示乱码,只能由对应程序读取;
  2. 存储紧凑、占用空间小、读写速度快
  3. 原样保存变量、结构体、数组,适合存大批量数据、自定义类型;
  4. 没有专门的换行分隔符。

流和标准流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输入、输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念。我们可以把流想象成流淌着的字符的河流。c 程序针对文件、画面、键盘等的数据输入,输出的操作都是通过流操作的,一般情况下我们想要向流里写数据,或者从流中读取数据,都要打开流,然后操作。

标准流

那为什么我们从键盘输入数据,向屏幕上输出数据并没有打开流?那是因为 c 语言程序在启动的时候默认打开了三个流:

  • stdin 标准输入流 → 绑定键盘,scanf函数就是从标准输入流中读取数据的
  • stdout 标准输出流 → 绑定显示器,printf函数就是将信息输出到标准输出流中
  • stderr 标准错误流 → 绑定显示器,大多数环境中输出到显示器界面

这默认打开了这三个流,我们使用 scanf、printf 的函数就可以直接进行输入,输出操作的。stdin、stdout、stder三个流是类型是:FILE*,通常称为文件指针。 C 语言通过 FILE 文件指针 管理流。

文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。在编写程序的时候,在打开文件的同时都会返回一个 FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

fclose

复制代码
语法:int fclose ( FILE * stream );
  • 头文件:#include <stdio.h>
  • 形参:文件指针 (必须是已经通过 fopen 成功打开的指针)
  • 返回值:
    • 关闭成功 :返回 0
    • 关闭失败 :返回 非 0 值

功能 关闭形参 stream 所关联的文件,解除文件指针和文件之间的关联

  1. 解除内部缓冲区与流的绑定;
  2. 刷新输出缓冲区 :缓冲区里还没写到磁盘的数据,全部写入文件(防止数据丢失);
  3. 清空输入缓冲区:缓冲区中还未读取的数据,直接丢弃。
  1. 参数FILE * 类型的流 / 文件指针。
  2. 返回值 :成功返回 0,失败返回非 0 值。

文件的顺序读写:

表格

函数名 函数原型 核心功能 关键参数 返回值 高频考点
fopen FILE *fopen (char *filename, char *mode); 打开文件,建立文件指针与文件的关联 filename:文件路径 / 名 mode:打开方式 成功:返回文件FILE*指针 失败:返回NULL 必须判断打开是否成功;路径转义符\\;打开方式的选用
fclose int fclose (FILE *stream); 关闭文件,解除指针与文件的关联,刷新缓冲区 stream:已打开的文件指针 成功:返回0 失败:返回非 0 值 必须配合fopen使用;防止数据丢失;释放系统资源
fprintf int fprintf (FILE*stream, char *format, 输出列表); 文本文件顺序写入,按格式将内存数据写入文件 stream:文件指针format:格式控制串 成功:返回写入的字符数 失败:返回负数 文本文件写专用;用法和printf几乎一致,仅多文件指针参数
fscanf int fscanf (FILE*stream, char *format, 地址列表); 文本文件顺序读取,从文件读取数据存入内存变量 stream:文件指针format:格式控制串 成功:返回成功读取的变量数失败 / 到文件尾:返回EOF 文本文件读专用;变量必须加&;和scanf用法一致
fwrite int fwrite (void *ptr, int size, int count, FILE *stream); 二进制文件顺序写入,按字节块写入数据 ptr:数据首地址size:单个数据字节数count:数据个数 成功:返回实际写入的完整数据块数 二进制文件写专用;适合数组 / 结构体 / 大批量数据
fread int fread (void *ptr, int size, int count, FILE *stream); 二进制文件顺序读取,按字节块读取数据 ptr:接收数据的内存地址其余参数同fwrite 成功:返回实际读取的完整数据块数 二进制文件读专用;和fwrite配对使用

表格

流名称 系统预设指针 对应设备 核心作用 常用函数
标准输入流 stdin 键盘 从键盘读取数据,输入到程序中 scanfgetcharfscanf(stdin,...)
标准输出流 stdout 显示器 把程序数据输出到屏幕上 printfputcharfprintf(stdout,...)
标准错误流 stderr 显示器 专门输出程序的错误、警告信息 报错提示专用

表格

打开方式 含义 核心规则 适用场景
r 只读(文本文件) 文件必须存在,否则打开失败;只能读,不能写 读取已有的文本文件数据
w 只写(文本文件) 文件不存在则新建;文件存在则清空原有全部内容,再写入 新建文本文件、覆盖原有文件内容
a 追加(文本文件) 文件不存在则新建;文件存在则在末尾续写内容,不覆盖原有数据 在已有文本文件末尾添加新内容
rb 只读(二进制文件) r,仅针对二进制文件 读取已有的二进制文件数据
wb 只写(二进制文件) w,仅针对二进制文件 新建 / 覆盖二进制文件
ab 追加(二进制文件) a,仅针对二进制文件 在二进制文件末尾续写内容

feof和ferror

表格

函数 原型 功能 返回值 使用场景
feof int feof(FILE *fp); 判断是否到达文件末尾 到文件尾:返回非 0 未到尾:返回0 循环读文件,判断是否读完
ferror int ferror(FILE *fp); 判断文件读写是否出错 出错:返回非 0 正常:返回0 检测读写过程

fputs和fgets

表格

函数 功能 原型 适用文件 核心特点
fputs 向文件写入字符串 int fputs(char *str, FILE *fp); 文本文件 不自动加换行、\0 不写入文件
fgets 从文件读取字符串 char *fgets(char *str, int n, FILE *fp); 文本文件 最多读 n-1 个字符;读到 \n 会一并存入;遇文件尾返回NULL

规则总览

  1. 正常读到 换行符 \n
    • 只要还没读满 n-1 位,会把 \n 一并存入数组
    • 然后自动追加 \0 作为字符串结束。
  2. 未遇到 \n,但字符数达到 n-1
    • 停止读取,不接收后续字符,也不收 \n
    • 末尾直接补 \0
  3. 读到文件末尾:返回 NULL

对比一组函数

一、输入类函数对比(scanf /fscanf/sscanf)

表格

函数名称 核心功能 标准函数原型 核心输入源 适用场景 核心特点 返回值规则 高频考点 / 易错点
scanf 标准输入流读取格式化数据 int scanf (const char *format, 地址列表); 键盘(终端) 日常程序的终端手动输入、控制台数据读取 1. 系统自动打开标准输入流,无需手动开关 2. 输入数据以空格 / 回车 / 制表符分隔 3. 是最基础、最常用的输入函数 成功:返回成功读取的变量个数 失败 / 输入结束:返回 EOF(-1) 1. 读取变量必须加取地址符&(最常考易错点) 2. 格式符必须与变量类型严格匹配 3. 无法读取带空格的完整字符串
fscanf 文件流读取格式化数据 int fscanf (FILE *fp, const char *format, 地址列表); 磁盘文本文件 从已打开的文本文件中读取数据、文件内容解析 1. 必须先通过fopen打开文件,获取有效文件指针fp 2. 用法与scanf几乎完全一致,仅多 1 个文件指针参数3. 按文件内容顺序读取,文件指针自动后移 成功:返回成功读取的变量个数 失败 / 到文件末尾:返回 EOF(-1) 1. 必须先判断文件是否打开成功(fp == NULL) 2. 仅适用于文本文件,二进制文件不推荐使用 3. 读取结束后必须用fclose关闭文件
sscanf 内存字符串中读取格式化数据 int sscanf (const char *str, const char *format, 地址列表); 内存中的字符数组 / 字符串常量 字符串解析、从已有字符串中提取指定格式数据、字符串拆分 1. 输入源是内存里的字符串,不涉及键盘 / 文件操作 2. 不会修改原字符串,仅从其中读取数据3. 可实现复杂的字符串格式提取,是字符串处理高频函数 成功:返回成功读取的变量个数 失败 / 字符串结束:返回 EOF(-1) 1. 第一个参数是字符串首地址,不是文件指针 2. 原字符串必须以\0结尾,否则会读取越界 3. 常与sprintf配对使用,实现字符串的格式化读写

二、输出类函数对比(printf /fprintf/sprintf)

表格

函数名称 核心功能 标准函数原型 核心输出目标 适用场景 核心特点 返回值规则 高频考点 / 易错点
printf 标准输出流输出格式化数据 int printf(const char *format, 输出列表); 显示器(终端屏幕) 日常程序的控制台结果输出、调试信息打印 1. 系统自动打开标准输出流,无需手动开关 2. 是最基础、最常用的输出函数 3. 输出内容直接显示在终端屏幕上 成功:返回成功输出的字符总数 失败:返回负数 1. 格式符必须与输出变量类型严格匹配2. 输出字符串时,数组名 / 指针无需加&3. 可通过\n实现换行、\t实现制表对齐
fprintf 文件流输出格式化数据 int fprintf(FILE *fp, const char *format, 输出列表); 磁盘文本文件 向已打开的文本文件写入数据、生成带格式的文本文件 1. 必须先通过fopen打开文件,获取有效文件指针fp 2. 用法与printf几乎完全一致,仅多 1 个文件指针参数 3. 按顺序写入文件,文件指针自动后移 成功:返回成功写入的字符总数 失败:返回负数 1. 必须先判断文件是否打开成功(fp == NULL) 2. 仅适用于文本文件,二进制文件不推荐使用 3. 写入结束后必须用fclose关闭文件,否则数据可能丢失
sprintf 内存字符串输出格式化数据 int sprintf (char *str, const char *format, 输出列表); 内存中的字符数组 字符串拼接、格式化生成新字符串、数字转字符串、字符串组装 1. 输出目标是内存里的字符数组,不涉及屏幕 / 文件操作 2. 自动在生成的字符串末尾添加结束符\0 3. 可实现复杂的字符串格式化拼接,是字符串处理高频函数 成功:返回成功写入的字符总数 (不含末尾的\0)失败:返回负数 1. 第一个参数是目标字符数组首地址,不是文件指针 2. 目标数组必须足够大,否则会造成缓冲区溢出(核心易错点) 3. 常与sscanf配对使用,实现字符串的格式化读写

文件的随机读写

基本概念

  1. 顺序读写:从文件开头往后依次读写,文件指针只能向后移动,不能跳转。
  2. 随机读写 :可人为移动文件指针,直接跳到文件任意位置读写,不用从头开始读。
  • 核心:靠 文件位置指针定位
  • 适用:二进制文件、结构体、数组(考试重点)

注意:随机读写一般搭配 二进制文件rb/wb),文本文件很少用。

表格

函数 功能 原型
fseek 移动文件位置指针(定位) int fseek(FILE *fp, long offset, int origin);
ftell 获取当前指针距离文件开头的字节数 long ftell(FILE *fp);
rewind 把指针重置到文件开头 void rewind(FILE *fp);

1. rewind () 重置文件指针到开头

1)功能

将文件位置指针直接跳回文件起始位置

2)语法

复制代码
rewind(FILE *fp);
  • 无返回值,无额外参数。

3)使用场景

读完一遍文件后,想从头再读一次 ,不用重新 fopen

示例

复制代码
rewind(fp);  // 指针回到文件开头

2. ftell () 获取当前指针位置

1)功能

计算当前文件指针 距离文件首部的字节数,返回字节偏移量。

2)语法

复制代码
long ftell(FILE *fp);
  • 返回值:long 类型,当前偏移字节数。

3)典型用途

文件总大小

复制代码
// 1.指针移到文件末尾
fseek(fp, 0, SEEK_END);
// 2.获取总字节数
long size = ftell(fp);
printf("文件大小:%ld 字节\n", size);

3. fseek () 重点(随机读写核心)

1)函数原型

复制代码
int fseek(FILE *fp, long offset, int origin);

三个参数逐个拆解(必背

参数 1:FILE *fp

已打开的文件指针(一般二进制文件 rb/wb

参数 2:long offset 偏移量
  • 正数:向文件尾部 向后移动
  • 负数:向文件头部 向前移动
  • 单位:字节
参数 3:int origin 参考起点(三种固定宏,必须记)

表格

宏名 数值 参考位置
SEEK_SET 0 文件开头(最常用)
SEEK_CUR 1 当前指针位置
SEEK_END 2 文件末尾

2)组合写法(高频定位)

  1. 文件开头向后移 10 字节

    fseek(fp, 10, SEEK_SET);

  2. 当前位置向后移 5 字节

    fseek(fp, 5, SEEK_CUR);

  3. 文件末尾向前移 8 字节(读最后一段数据)

    fseek(fp, -8, SEEK_END);

  4. 等价于 rewind(回到开头)

    fseek(fp, 0, SEEK_SET);

3)返回值

  • 定位成功:返回 0
  • 定位失败:返回 非 0 值

文件缓冲区

相关推荐
Scott9999HH6 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海7 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区11 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大11 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai11 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜12 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa12 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio