【落羽的落羽 C语言篇】文件操作

文章目录
- 一、文件的概念和分类
- 1. 概念和分类
- 2. 文件名
- 3. 数据文件
- 三、文件操作
- 1. 文件的打开和关闭
- 1.1 流
- 1.2 文件指针
- 1.3 文件的打开和关闭
- 2. 文件的顺序读写
- 3. 文件的随机读写
- 4. 文件读取的判定
- 5. 文件缓冲区
一、文件的概念和分类
1. 概念和分类
文件是用来保存数据的。如果没有文件,我们写的程序会直接存储在电脑内存中,如果程序退出,内存被释放回收,数据就丢失了。所以如果要将数据进行持久化的保存,我们就可以使用文件来保存数据。
在生活中,我们一般直接将电脑磁盘中的文件称之为文件。而在程序设计中,我们所说的文件一般分为两种:程序文件、数据文件。
- 程序文件包括:源程序文件(后缀为.c)、目标文件(Windows环境下后缀为.obj)、可执行程序(后缀为.exe)以后会再次介绍的。
- 数据文件的内容,是程序运行时读写的数据,包括程序运行时需要从中读取数据的文件,或者输出内容的文件。
在之前C语言的学习过程中,我们对数据的输出输入都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。但有时候我们也需要把数据输出到磁盘中,也需要从磁盘中读取数据到内存中来使用,这时就是对磁盘里的文件进行文件操作了。
2. 文件名
我们还要知道的是:一个文件通常要有一个唯一的文件标识以便于使用者识别和引用,这就是文件名,通常包含“文件路径、文件名主干、文件后缀”三部分。
举个例子,在我的电脑磁盘中有:
右键点击复制文件地址,能得到这个文件的文件名是:
D:\ACG电吉\春日影\Final春日影 吉他.pdf
其中,这个文件本身的名字“Final春日影 吉他”,是文件名主干。
前面的“D:\ACG电吉\春日影\”,是文件路径。
最后的“.pdf”,是文件后缀。
很简单对吧。
3. 数据文件
数据文件还可以再分为文本文件和二进制文件。
- 文本文件:数据以ASCII值的形式存储的文件
- 二进制文件:数据以二进制的形式存储的文件
字符型数据一律用ASCII值形式存储,数值型数据既可以用ASCII值形式存储也可以用二进制形式存储。
它们的区别是什么呢?举个栗子,整数12345
- 如果以ASCII形值式输出到磁盘中,则占用五个字节(一个字符占据一个字节),内容是00110001 00110010 00110011 00110100 00110101(即ASCII值49、50、51、52、53,对应字符“1”、“2”、“3”、“4”、“5”)
- 如果以二进制形式输出到磁盘中,则占用四个字节(int大小),内容是00000000 00000000 00110000 00111001(就是12345的二进制表示)

三、文件操作
1. 文件的打开和关闭
1.1 流
流是计算机领域一个抽象但重要的概念。
简单来说,程序需要跟各种外部设备交互,外部设备包括键盘、显示器、磁盘、U盘、网络等等,程序的数据需要输出到各种外部设备上,也需要从各种外部设备获取数据,不同的外部设备的输入输出操作各不相同。为了方便程序员对各种设备的操作,人们抽象出了“流”的概念。“流”就像一条流淌着数据的河,程序和外部设备将数据都投入这条“河”中,或者各取所需的数据。C语言内部处理好外部设备和流的数据传递,而程序设计者只要再考虑程序如何与流交互就好了。
一般情况下,我们想要往流里写数据,或者从流里读取数据,都是先打开流,然后再操作。
那么,为什么我们以前写C语言程序,从键盘上读取数据,向屏幕上输出数据,并没有打开流的操作呢?这是因为C语言程序在启动时,默认会打开三个流:
- stdin(标准输入流):它在大多数环境下能从键盘输入数据,scanf函数就是从这个流中读取数据的
- stdout(标准输出流):它在大多数环境下能输出数据至显示器界面,printf函数就是将信息输出到这个流中的
- stderr(标准错误流):它在大多数环境下能输出数据至显示器界面
这三个流的类型是FILE*,被称为文件指针。在C语言中,就是通过文件指针来维护流的各种操作的。
1.2 文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,比如文件的名字、状态、位置等等。这些信息被保存在一个结构体变量中,该结构体变量是由系统声明的,被typedef重命名为FILE。不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
使用者打开一个文件时,系统会根据文件的情况自动创建一个FILE类型的变量,自动填充好内部信息,使用者不必关心具体细节。
为了维护这个FILE结构的变量,一般使用FILE*类型的指针,这就是文件指针。比如,定义一个FILE* pf;可以使pf指向某个文件的文件信息区,通过该文件信息区的信息来操作该文件,换句话说,通过文还指针能够间接找到与它相关联的文件。
1.3 文件的打开和关闭
读写文件之前应该先打开文件,使用后应该关闭文件。ANSI C规定使用fopen函数打开文件,fclose函数关闭文件。它们(和以下函数)包括在头文件stdio.h中

fclose的使用方式很简单,参数就是需要关闭的文件的文件指针。
fopen的使用较为复杂:
FILE* fopen(const char* filename, const char* mode);
它的返回值是打开的文件的文件指针。
它的第一个参数是文件名,第二个参数是文件的打开模式,有以下模式及其作用:
| 文件打开模式 | 含义 | 如果指定文件不存在 |
|---|---|---|
| r(只读) | 为了输入数据,打开一个文本文件 | 返回空指针 |
| w(只写) | 为了输出数据,打开一个文本文件 | 创建一个新的文件(如果文件存在,会清空原内容) |
| a(追加) | 向文本文件尾添加数据 | 创建一个新的文件 |
| rb(只读) | 为了输入数据,打开一个二进制文件 | 返回空指针 |
| wb(只写) | 为了输出数据,打开一个二进制文件 | 创建一个新的文件 |
| ab(追加) | 向二进制文件尾添加数据 | 创建一个新的文件 |
| r+(读写) | 为了读写数据,打开一个文本文件 | 返回空指针 |
| w+(读写) | 为了读写数据,打开一个文本文件 | 创建一个新的文件 |
| a+(读写) | 在文本文件尾读写数据 | 创建一个新的文件 |
| rb+(读写) | 为了读写数据,打开一个二进制文件 | 返回空指针 |
| wb+(读写) | 为了读写数据,创建一个二进制文件 | 创建一个新的文件 |
| ab+(读写) | 在二进制文件尾读写数据 | 创建一个新的文件 |
举例,一开始我的项目文件夹里没有data.txt这个文件
如果有FILE* pf = fopen("data.txt","r");:
如果是FILE* pf = fopen("data.txt","w");就会在这个代码项目的文件夹中创建这样一个文件:

当然,我们还可能需要从电脑的其他磁盘上的其他文件中读写数据,就需要明白绝对路径和相对路径的表示方法:
- 绝对路径就是一个文件的完整文件名,比如之前提到过的 D:\ACG电吉\春日影\Final春日影 吉他.pdf
- 相对路径要用
.或..表示,.表示当前路径,..表示上一级路径。每一级中间本来需要用\分割,但在C语言中需要被转义,即要用转义字符\\表示\
举个栗子,我的电脑中一开始没有data.txt这个文件,我的C语言程序源文件位置如下:

如果在程序中以w模式打开一个D盘文件data.txt,就会自动创建
- 用绝对路径表示:
fopen("D:\\data.txt","w"); - 用相对路径表示:
fopen(".\\..\\..\\..\\..\\data.txt","w");

都是成功的
2. 文件的顺序读写
文件的顺序读写涉及到一系列函数:
| 函数 | 功能 | 适用于 |
|---|---|---|
| fgetc | 字符输入 | 所有输入流 |
| fputc | 字符输出 | 所有输出流 |
| fgets | 按文本行输入 | 所有输入流 |
| fputs | 按文本行输出 | 所有输出流 |
| fscanf | 格式化输入 | 所有输入流 |
| fprintf | 格式化输出 | 所有输出流 |
| fread | 二进制输入 | 文件输入流 |
| fwrite | 二进制输出 | 文件输出流 |
这些函数的使用大同小异,我们就举两个例子,其余大家自己查阅了解即可
fputs函数的第一个参数是要写入的字符串,第二个参数是要写进的文件
fgetc函数的参数是要从中读取字符的文件
#include<stdio.h>
int main()
{FILE* pf = NULL;pf = fopen("data.txt", "w");fputs("TECH OTAKUS SAVE THE WORLD", pf);fclose(pf);pf = fopen("data.txt", "r");int n = 0;while(n++ < 5)printf("%c\n", fgetc(pf));fclose(pf);return 0;
}
结果很显然,程序创建了一个文本文件写入了一些内容,然后打印出前四个字符。


3. 文件的随机读写
上面的函数只能对文件内容按顺序读写,有时我们也需要对内容按照特定顺序读写,这就是文件的随机读写。要用到以下函数:
-
fseek
这个函数能改变文件光标的位置,“文件光标”就是读写数据的位置,可以理解成我们在电脑手机上打字的这个光标。

第一个参数是文件指针,第二个参数是你想要的偏移量,第三个参数是你想从哪个位置计算偏移量。第三个参数是有三个取值的:
SEEK_SET是文件的开头,SEEK_CUR是当前光标的位置,SEEK_END是文件的末尾。
光标位置是怎么决定的呢?比如文件指针pf刚刚进行了写数据,其指向的文件里刚写下了abcdef,此时光标在末尾,即f后的位置。如果有fseek(pf, 2, SEEK_SET);光标在文本开头后偏移2个位置,即b和c中间。假如我们再写一次数据,就会从这里开始写,新写入的数据会覆盖掉刚才的几个字符:
偏移量负值代表左偏移,正值代表右偏移。所以,对于abcdef,fseek(pf, 2, SEEK_SET)和fseek(pf, -4, SEEK_END)的效果其实是一样的再举例一个用法,fgetc读取字符是从文件开头向后一个一个读的。因为光标起始位置是开头,每次读光标之后的一个字符,然后光标向右偏移1。但我们不想按这样的顺序读数据时,就可以用fseek函数实时调整光标的位置了。
-
ftell
很简单,它的参数是文件指针,这个函数能返回这个文件中当前光标相对于开头的偏移量 -
rewind
这个函数能让参数文件的光标返回起始位置
4. 文件读取的判定
不同的函数读取到文件末尾时的标识不一样,比如fgets读取结束会返回NULL,fgetc读取结束会返回EOF,等等。对于二进制文件,fread的返回值小于实际要读取的个数,说明读取结束
5. 文件缓冲区
最后一个简单的知识点:ASNI C标准采用“缓冲文件系统”处理数据文件,它指系统自动在内存中为程序每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据,会先送到文件缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机输入数据,则从磁盘文件中读取数据输入到内存缓冲区,然后再从缓冲区逐个地将数据送到程序数据区。缓冲区的大小由C编译系统决定。因为由缓冲区的存在,所以C语言在进行文件操作时,需要刷新缓冲区或者结束时关闭文件。如果不做,可能有读写文件的问题。

本篇完,感谢阅读~
相关文章:
【落羽的落羽 C语言篇】文件操作
文章目录 一、文件的概念和分类1. 概念和分类2. 文件名3. 数据文件 三、文件操作1. 文件的打开和关闭1.1 流1.2 文件指针1.3 文件的打开和关闭 2. 文件的顺序读写3. 文件的随机读写4. 文件读取的判定5. 文件缓冲区 一、文件的概念和分类 1. 概念和分类 文件是用来保存数据的。…...
RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)
0.前言 递归!循环神经网络Recurrent Neural Network 循环神经网络(又称递归神经网络,Recurrent Neural Network,RNN)。是一种用于处理序列数据的神经网络结构,具有记忆功能,能够捕捉序列中的时…...
战略与规划方法——深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具
深入解析波士顿矩阵(BCG Matrix):分析产品组合的关键工具 在现代商业管理中,合理地分析和管理产品组合对于企业的成功至关重要。波士顿矩阵(BCG Matrix),又称为成长份额矩阵,是一种由波士顿咨询集团(Boston Consulting Group)在20世纪70年代提出的战略工具,用于帮助…...
【记录52】el-table-column 添加fixed属性 滚动条无法滑动
问题: el-table-column 添加fixed属性 滚动条无法滑动 使用element UI组件,用到el-table的el-table-column的fixed属性时,当滚动条长度小于固定列时,滚动条无法通过鼠标去点击滑动操作 原因 fixed是用来固定列的属性,其…...
晨辉面试抽签和评分管理系统之十:如何搭建自己的数据库服务器,使用本软件的网络版
晨辉面试抽签和评分管理系统(下载地址:www.chenhuisoft.cn)是公务员招录面试、教师资格考试面试、企业招录面试等各类面试通用的考生编排、考生入场抽签、候考室倒计时管理、面试考官抽签、面试评分记录和成绩核算的面试全流程信息化管理软件。提供了考生…...
主链和Layer2之间资产转移
主链和Layer2之间资产转移 主链和Layer2之间资产转移是实现Layer2技术的关键环节,以下是资产转移的流程、流行解决方案及原理: 资产从主链转移到Layer2 用户在主链上发起一笔交易,将资产发送到一个特定的智能合约地址,这个合约是主链与Layer2之间的桥梁。智能合约会锁定用…...
麒麟操作系统服务架构保姆级教程(十)rewrite跳转
如果你想拥有你从未拥有过的东西,那么你必须去做你从未做过的事情 我们访问一个网页的时候会遇到一些奇形怪状的url地址,想优化一下,看着顺眼一点,或者打开一个短视频软件想摸鱼刷一会视频,在打开界面的时候无意间按到…...
MySQL表的创建实验
创建并使用数据库mydb6_product 。 mysql> create database mydb6_product; Query OK, 1 row affected (0.01 sec)mysql> use mydb6_product; Database changed 新建employees表。 对于gender,有默认值意味着不为空,在建表时可以选择不写not nul…...
【高可用自动化体系】自动化体系
架构设计的愿景就是高可用、高性能、高扩展、高效率。为了实现架构设计四高愿景,需要实现自动化系统目标: 标准化。 流程自助化。 可视化:可观测系统各项指标、包括全链路跟踪。 自动化:ci/cd 自动化部署。 精细化:…...
总结SpringBoot项目中读取resource目录下的文件多种方法
系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目…...
Java-KMP字符串匹配算法
给两个字符串s和t,如何很快的知道s是否包含t(即t是否是s的子串)。暴力的方法,我们依次以s每个位置为头,去匹配t。 public int find(String s, String t) {char[] ss s.toCharArray();char[] tt t.toCharArray();int …...
Vue3使用vue-count-to数字滚动模块报错解决方案
小伙伴们是不是遇到了vue3项目使用vue-count-to出现报错的问题 报错如下: TypeError: Cannot read properties of undefined (reading _c) 这个错误信息具体是说没读取到_c的属性 具体不清楚是什么原因,排查还得去看源码,所以我们来解决&a…...
【高阶数据结构】线段树加乘(维护序列)详细解释乘与加懒标记
文章目录 1.题目[AHOI2009] 维护序列 2.懒标记处理先加后乘的形式1. 先加后乘的操作 先乘后加的形式2. 先乘后加的操作**乘法操作****加法操作** 懒标记的下传 3.代码 1.题目 题目来源:https://www.luogu.com.cn/problem/P2023 [AHOI2009] 维护序列 题目背景 老师交给小可可…...
replaceState和vue的router.replace删除query参数的区别
使用history.replaceState /*** 替换当前的 history state和url* param {(searchParams:URLSearchParams)>any} cb*/ export const replaceUrlSearch (cb) > {// 获取当前 URLconst url new URL(window.location.href)// 获取 URL 的查询参数const searchParams new …...
[USACO14JAN] Ski Course Rating G
题目大意 滑雪场用一个 N ∗ M N*M N∗M 的整数矩阵表示海拔高度,每个整数表示一个范围在 1 0 9 10^9 109 的高度。每个格子都可以滑到相邻的格子,爱好者们将会在雪场种尽情享受。有些格子被指定为起点,每个起点都要进行评级以帮助爱好者选…...
初步认识 Neo4j 图数据库
Neo4j 是一种高性能的图数据库管理系统,基于图论设计,能够高效地存储和查询复杂的关系数据。以下是关于 Neo4j 的详细介绍: 核心特性 数据模型: Neo4j 使用图数据模型,将数据以节点(Node)、关系…...
Qt中容器 QVector、QList、QSet和QMap 性能与用途比较
表格汇总: 容器存储结构随机访问性能插入/删除性能主要用途QVector连续存储的动态数组 O ( 1 ) O(1) O(1)末尾: O ( 1 ) O(1) O(1),中间: O ( n ) O(n) O(n)频繁随机访问,末尾元素的添加/删除QList优化存储࿰…...
ASP.NET Core - 依赖注入(四)
ASP.NET Core - 依赖注入(四) 4. ASP.NET Core默认服务5. 依赖注入配置变形 4. ASP.NET Core默认服务 之前讲了中间件,实际上一个中间件要正常进行工作,通常需要许多的服务配合进行,而中间件中的服务自然也是通过 Ioc…...
数学用语中 up to 的含义
1. 问题 在数学用语中,常见到“up to”这种用法, 但这种用法与我们常规情况下的用法不同,常令人困惑。 2. “等价关系”说明 已知两个数学对象 a 和 b,以及实数域R, • 当 a 和 b是通过 R 关联的࿰…...
Spring Boot + MyBatis-Flex 配置 ProxySQL 的完整指南
✅ Spring Boot MyBatis-Flex 配置 ProxySQL 的完整指南 下面是一个详细的教程,指导您如何在 Spring Boot 项目中使用 MyBatis-Flex 配置 ProxySQL 进行 读写分离 和 主从同步 的数据库访问。 🎯 目标 在 Spring Boot 中连接 ProxySQL。使用 MyBatis-…...
OpCore Simplify技术突破:如何用智能适配重构开源系统定制效率
OpCore Simplify技术突破:如何用智能适配重构开源系统定制效率 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 在开源系统定制领域&#x…...
Node.js——util工具模块
util工具模块1、util模块概述2、util模块的使用2.1、格式化输出字符串2.2、将对象转换为字符串(调试)2.3、实现对象间的原型继承2.4、转换异步函数的风格2.5、判断是否为指定类型的内置对象2.6、其它方法1、util模块概述 util模块是Node.js的内置模块&a…...
嵌入式监控DIY:用RV1126开发板和任意UVC摄像头搭建低成本RTSP视频服务器
嵌入式监控DIY:用RV1126开发板和任意UVC摄像头搭建低成本RTSP视频服务器 在智能家居和工业物联网快速发展的今天,视频监控系统的需求日益增长。传统监控方案往往价格昂贵且灵活性不足,而基于嵌入式开发板和普通USB摄像头的DIY方案则提供了高性…...
Verilog仿真踩坑记:为什么你的测试用例‘通过’了,但电路其实是错的?(附X态检测代码)
Verilog仿真中的X态陷阱:如何避免“虚假通过”的致命错误 数字电路仿真中,最危险的场景莫过于测试结果显示“Passed”,但实际芯片却存在严重功能缺陷。这种“虚假通过”现象往往源于Verilog中X态(未知状态)的隐蔽特性…...
告别轮询!GD32F407 ADC+DMA+定时器触发,实现多通道自动采集与存储
GD32F407 ADCDMA定时器触发:多通道自动采集系统设计指南 在物联网节点和工业监测设备开发中,高效稳定的数据采集系统是核心基础。传统轮询式ADC采集不仅占用大量CPU资源,还难以满足多通道同步、高精度定时采集的需求。本文将深入讲解基于GD32…...
Qwen3-14B私有化效果闭环:从部署→使用→反馈→迭代的完整链路
Qwen3-14B私有化效果闭环:从部署→使用→反馈→迭代的完整链路 1. 开箱即用的私有化部署方案 Qwen3-14B作为通义千问系列的最新大语言模型,在14B参数规模下展现出惊人的理解与生成能力。但对于企业用户而言,如何在自有环境中实现稳定、高效…...
智慧小区网络设计避坑指南:华为设备选型、无线覆盖与安全策略实战解析
智慧小区网络设计实战:华为设备选型与无线覆盖避坑指南 当接到智慧小区网络建设项目时,很多工程师会陷入理论完美主义陷阱——画出漂亮的拓扑图,却在实际部署中遭遇信号死角、设备过载、策略冲突等现实问题。本文将从三个真实项目复盘出发&am…...
EVA-02模型辅助软件测试:自动化生成测试用例与边界条件描述
EVA-02模型辅助软件测试:自动化生成测试用例与边界条件描述 如果你是一名软件测试工程师,下面这个场景你一定不陌生:产品经理递过来一份几十页的需求文档,你需要在几天内,把它拆解成成百上千条逻辑清晰、覆盖全面的测…...
CogVideoX-2b完整功能测评:一键部署+本地渲染+隐私安全全解析
CogVideoX-2b完整功能测评:一键部署本地渲染隐私安全全解析 1. 为什么选择本地化视频生成工具 在内容创作领域,视频制作一直是门槛较高的技能。传统视频制作需要专业的剪辑软件、大量的素材积累以及复杂的时间线操作。而云端视频生成服务虽然降低了技术…...
揭秘C++多态:动态行为的核心奥秘
C 多态:面向对象的动态行为核心机制多态性是面向对象编程(OOP)的核心概念之一,它允许对象在运行时根据其实际类型表现出不同的行为。在C中,多态性主要通过虚函数(virtual functions)和继承机制实…...
