C语言之旅:文件操作

目录

一什么是文件

1.1程序文件:

1.2数据文件:

1.3文件名

二.文件的打开与关闭

2.1流和标准流

2.2 文件指针

 2.3文件的打开与关闭

 三.文件的顺序读写

3.1顺序读写函数介绍

fgetc

fputc

fgets

fputs

四.文件的随机读写

4.1 fseek

4.2 ftell

4.3 rewind

五.文件读取结束的判定

文件缓冲区


一什么是文件

文件是数据按特定格式或协议存储在外部介质上的一种数据集合。文件通常是存储在计算机存储介质上,如硬盘、光盘、磁带等,也可以是存储在外部设备或网络中。

但是在程序设计中,我们⼀般谈的文件件有两种:程序文件、数据文件(从文件功能的文件度来分类 的)。

1.1程序文件:

这类文件包含源程序文件、目标文件或可执行程序。

源程序文件:

通常以 .c、.cpp、.java 等作为后缀,它们包含程序员编写的源代码,这些源代码需要被编译器或解释器转换为可执行代码才能在计算机上运行。

目标文件:

在编译过程中产生的中间文件,例如在 Windows 环境下通常以 .obj 为后缀。这些文件包含编译器从源程序文件生成的机器语言代码,但通常还不能直接运行,需要链接器进一步处理。

可执行程序:

这是经过编译和链接后生成的文件,可以直接在计算机上运行。在 Windows 环境下,可执行程序通常以 .exe 为后缀。

1.2数据文件:

文件的内容不⼀定是程序,⽽是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

本章讨论的是数据文件。

在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输⼊数据,运行结果显示到显示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处 理的就是磁盘上文件。

1.3文件名

⼀个文件要有⼀个唯⼀的文件标识,以便用户识别和引用。

文件名包含3部分:文件路径+文件名主干+文件后缀

二.文件的打开与关闭

2.1流和标准流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出 操作各不相同,为了⽅便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。

C程序针对文件、画面、键盘等的数据输⼊输出操作都是通过流操作的。⼀般情况下,我们要想向流里写数据,或者从流中读取数据,都是要打开流,然后操作。

标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?

那是因为C语⾔程序在启动的时候,默认打开了3个流:

•stdin标准输⼊流,在大多的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。

 • stdout标准输出流,大多数的环境中输出至显示器界⾯,printf函数就是将信息输出到标准输出 流中。

• stderr标准错误流,大多数环境中输出到显示器界面。

这是默认打开了这三个流,我们使用scanf、printf等函数就可以直接进行输⼊输出操作的。

 stdin、stdout、stderr三个流的类型是: FILE* ,通常称为文件指针。

2.2 文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

文件指针在C语言中是一个用于指向文件的变量。这个指针通常是一个指向FILE结构体类型的指针。

VS2022编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:

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

不同的C编译器的FILE类型构的包含的内容不完全相同,但是大同小异。每当打开⼀个文件的时候,系统会根据文件的情况自动创建⼀个FILE结变量,并填充其中的信 息,使用者不必关心细节。

⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加方便。

FILE* pf;

定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是⼀个结构体变 量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够间接找到与 它关联的文件。

 2.3文件的打开与关闭

文件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭文件。

在编写程序的时候,在打开文件的同时,都会返回⼀个FILE*的指针变量指向该文件,也相当于建立了 指针和文件的关系。

ANSIC规定使用 fopen 函数来打开文件, fclose 来关闭文件。

fopen

函数原型:

FILE *fopen(const char *filename, const char *mode);

filename:要打开或创建的文件的名称(包括路径,如果需要的话)。
mode:指定文件打开模式的字符串。这些模式字符串决定了文件应该如何被打开以及你可以如何使用这个文件。

文件的打开模式:

文件的使用方式含义如果指定不存在
“r”(只读)为了输⼊数据,打开⼀个已经存在的文本文件出错
“w”(只写)为了输出数据,打开⼀个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据建立一个新的文件
rb”(只读为了输入数据,打开⼀个⼆进制文件出错
“wb”(只写)为了输出数据,打开⼀个⼆进制文件建立一个新的文件
“ab”(追加)向⼀个⼆进制文件尾添加数据建立⼀个新的文件
“r+”(读写)为了读和写,打开⼀个文本文件出错
“w+”(读写为了读和写,建议⼀个新的文件建立一个新的文件
“a+”(读写打开⼀个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开⼀个⼆进制文件出错
“wb+”(读 写)为了读和写,新建⼀个新的⼆进制文件建立⼀个新的文件
“ab+”(读 写)打开⼀个⼆进制文件,在文件尾进⾏读和写建立⼀个新的文件

fclose

函数原型:

int fclose(FILE *stream);

FILE *stream:这是一个指向 FILE 对象的指针,该对象标识了要被关闭的文件。这个指针通常是通过 fopen、freopen 或 fdopen 函数返回的。

返回值:如果成功关闭了文件,fclose 返回零(0)。如果发生错误,返回非零值(EOF )。

代码实现:

#include <stdio.h>int main() 
{FILE* fp;// 以写入模式打开文件  fp = fopen("test.txt", "w");if (fp == NULL) {printf("无法打开文件\n");return 1;}// 写入数据到文件  fprintf(fp, "Hello, World!\n");// 关闭文件  fclose(fp);return 0;
}

 三.文件的顺序读写

3.1顺序读写函数介绍

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

fgetc

代码实现:

        

#include <stdio.h>  int main() 
{FILE* pf;char ch;// 打开文件  pf = fopen("test.txt", "r");if (pf == NULL) {perror(" fopen fail");return 1;}// 逐字符读取文件内容      while ((ch = fgetc(pf)) != EOF) {printf("%c",ch); // 输出读取到的字符  }// 关闭文件  if (fclose(pf) != 0) {perror("fclos fail");return 1;}return 0;
}

fputc

函数原型:

int fputc(int character, FILE *stream);

character:需要写入的字符。虽然该参数被定义为 int 类型,但实际上它只使用 int 类型的低八位,并将其作为无符号字符来处理。

stream:要写入字符的文件流。这通常是通过 fopen 函数打开的文件。

#include <stdio.h>
int main() 
{FILE* pf;// 打开文件  pf = fopen("test.txt", "r");if (pf == NULL) {perror("fopen fail");return 1;}// 将字符 'A' 写入文件  fputc('A', pf);int ch = fgetc(pf);printf("读取的字符 %c",ch);// 关闭文件  if (fclose(pf) != 0) {perror("fclose fail");return 1;}return 0;
}

 输出结果:

fgets

函数原型:

char *fgets(char *str, int n, FILE *stream);

str:指向一个字符数组的指针,该数组将存储从文件读取的字符串。
n:指定要读取的最大字符数(包括最后的空字符,但通常不包括换行符)。通常,这个值设置为数组的大小。
stream:指向要读取的文件的指针。

返回值:

如果成功,fgets 将返回一个指向 str 的指针。
如果发生错误或到达文件末尾(EOF),fgets 将返回 NULL。

fputs

函数原型:

int fputs(const char *str, FILE *stream);

 str:要写入文件的字符串。
stream:一个指向 FILE 对象的指针,该对象标识了要写入字符的流 

代码实现:
 

#include<stdio.h>
int main()
{FILE* pf;char* arr = "hello world"; // 打开目标文件  pf = fopen("test.txt", "w"); //写入数据if (pf == NULL){perror("fopen fail");return 1;}fputs(arr, pf);//关闭文件fclose(pf);pf = fopen("test.txt", "r");//读取数据if (pf == NULL){perror("fputs fail");return 1;}char line[100];while (fgets(line, sizeof(line), pf) != NULL){printf("%s", line);}// 关闭文件  fclose(pf);return 0;
}

四.文件的随机读写

4.1 fseek

函数原型:

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

其中,参数stream表示文件指针;offset表示要移动的字节数,可以是正数或负数;origin表示起始位置

有三种取值:

SEEK_SET从文件开头开始计算偏移量
SEEK_CUR从当前位置开始计算偏移量
SEEK_END从文件末尾开始计算偏移量
#include <stdio.h>int main()  
{FILE* pf = fopen("test.txt", "r");if (pf == NULL) {perror("打开文件失败"); return 1; }// 将文件指针移动到文件的第四个字节fseek(pf, 3, SEEK_SET); // SEEK_SET表示从文件开始位置计算偏移量  // 读取当前文件指针指向的字符  int ch1 = fgetc(pf); if (ch1 != EOF) {printf("第四个字符是:%c\n", ch1); }else{printf("读取第四个字符失败\n");} if (fseek(pf, -1, SEEK_END) == 0) // -1表示向前移动一个字节  {// 读取当前指针指向的字符  int ch2 = fgetc(pf); if (ch2 != EOF)  {printf("文件末尾之前的字符是:%c\n", ch2); }else{printf("读取失败\n");   }}else{printf("无法定位到文件末尾之前的位置\n"); }  //关闭文件fclose(pf); return 0; 
}

 输出结果:

4.2 ftell

函数原型:

long ftell(FILE *stream);

stream:这是一个指向 FILE 对象的指针,该对象标识了一个打开的文件流。

#include<stdio.h>
int main() {FILE* pf = fopen("test.txt", "r");if (pf == NULL) {perror("fopen");return 1;} fseek(pf,0,SEEK_END);long size = ftell(pf);// 关闭文件  fclose(pf);printf("文件长度:%ld\n",size);return 0;
}

4.3 rewind

作用是将文件内部的位置指针重新指向一个流的开头

函数原型:

void rewind ( FILE * stream );

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);return 0;
}

五.文件读取结束的判定

被错误使⽤的 feof 牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。 feof 的作用是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。

1.文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )

例如:

• fgetc 判断是否为 EOF 。

• fgets 判断返回值是否为 NULL 。

文件缓冲区

ANSIC标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为 程序中每⼀个正在使用的文件开辟⼀块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓 冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输 入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

#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);//刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘) //注:fflush 在⾼版本的VS上不能使⽤了 printf("再睡眠10秒-此时,再次打开test.txt⽂件,⽂件有内容了\n");Sleep(10000);fclose(pf);//注:fclose在关闭⽂件的时候,也会刷新缓冲区 pf = NULL;return 0;
}

 刷新前:

刷新后:

这里可以得出一个结论:  

因为有缓冲区的存在,C语⾔在操作文件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭⽂ 件。 如果不做,可能导致读写文件的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/12722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【案例教程】土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测

查看原文>>>土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测 土地利用/土地覆盖数据是生态、环境和气象等领域众多模型的重要输入参数之一。基于遥感影像解译&#xff0c;可获取历史或当前任何一个区域的土地利用/土地覆盖数据&#xff0c;用于评估区域的生…

I2C总线协议

目录 一、前言 二、概念 三、I2C总线 1、主从结构 2、两线 3、半双工 4、上拉电阻 5、高阻态 四、时序图 1、起止信号 2、数据传输 3、应答信号 五、数据传送 1、传送格式 2、读写数据 六、时钟同步与仲裁 1、时钟同步 2、仲裁 七、时钟拉伸 八、总线速率 一、…

Flutter 依据JSON数据自动生成实体类

json自动化生成工具 点击这里可以跳转 页面是这样的 然后在左边输入你的json数据&#xff0c;它会自动生成对应的实体类 生成的实体类是如下&#xff1a; import package:json_annotation/json_annotation.dart; part merch_region.g.dart;JsonSerializable()class MerchReg…

国网645协议报文解析软件

本文分享一款支持国网DL645-2007规约的报文解析软件&#xff0c; 链接: https://pan.baidu.com/s/1ngbBG-yL8ucRWLDflqzEnQ 提取码: y1de 主界面如下图所示&#xff1a; 本解析软件同时内嵌规约文档&#xff0c;支持一键打开文档&#xff0c;功能如下&#xff1a; 同时支持模…

堆的数组实现

前言 本次博客来讲解一下堆的数组实现&#xff0c;好吧还是会结合图例&#xff0c;让大家理解 堆的定义 什么是堆&#xff1f; 堆是一颗完全二叉树。它的性质是父节点一定大于或者一定小于子节点 每一个结点都要满足这个性质就是堆 堆的特性是堆顶的数据一定是最大或最小…

ROS仿真多点导航

仿真环境启动&#xff1a; 1、启动并进入到相应环境&#xff1a; roscarroscar-virtual-machine:~/artcar_simulation$ 启动gazebo环境&#xff1a; roslaunch artcar_gazebo artcar_gazebo.launch 启动move_base&#xff1a; roslaunch artcar_nav artcar_move_base.launc…

3D数字化技术如何改变汽车行业?

近年来&#xff0c;新能源汽车行业加速发展&#xff0c;新车型密集发布&#xff0c;汽车保有量和车龄的增加&#xff0c;也同时点燃了汽车后市场的增长引擎。对于车企而言&#xff0c;如何全方面优化汽车从研发、生产、售后到营销的各个环节&#xff0c;以便适应快速变化的市场…

使用make_blobs生成数据并使用KNN机器学习算法进行分类和预测以及可视化

生成数据 使用make_blobs生成数据并使用matplotlib进行可视化 完整代码&#xff1a; from sklearn.datasets import make_blobs # KNN 分类器 from sklearn.neighbors import KNeighborsClassifier # 画图工具 import matplotlib.pyplot as plt # 数据集拆分工具 from sklea…

Win7远程桌面连接不上:原因及专业解决方案

Win7远程桌面连接作为一种方便的工具&#xff0c;使得用户可以从一台计算机远程访问和操作另一台计算机。然而&#xff0c;有时用户可能会遇到Win7远程桌面连接不上的情况&#xff0c;这可能是由于多种原因导致的。 一、原因分析 1. 网络设置问题&#xff1a;确保计算机与远程…

可用在vue自动导入的插件unplugin-auto-import

在大多数vue3开发中&#xff0c;基本所有页面都会引用vue3 componsition api&#xff0c;如下代码 想这种vue3 架构中自带的api&#xff0c;如果在全局配置一下的话&#xff0c;就可以减少一部分代码量&#xff0c;只是在代码编译的时候&#xff0c;会添加相应的引用&#xff…

【Stable Diffusion】 训练方法篇

一、四种模型训练方法简介 Stable Diffusion 有四种训练模型的方法&#xff1a;Textual Inversion、Hypernetwork、LoRA 和 Dreambooth 。它们的训练方法存在一定差异&#xff0c;我们可以通过下面对比来评估使用哪种训练方式最适合你的项目。 如果你知道模型中已经可以产生你…

企业架构系统之-IT系统建设如何做好技术选型

背景 近日有幸与行业同仁交流工作心得&#xff0c;在讨论中&#xff0c;他们提到一个平时工作当中我们都会遇到和经历的一个问题&#xff1a;作为架构师&#xff0c;在日常工作中应如何进行技术选型&#xff1f;面对众多框架和组件中&#xff0c;我们又应如何选择&#xff0c;…

Postgresql源码(128)深入分析JIT中的函数内联llvm_inline

相关 《Postgresql源码&#xff08;127&#xff09;投影ExecProject的表达式执行分析》 《LLVM的ThinLTO编译优化技术在Postgresql中的应用》 《LLVM&#xff08;5&#xff09;ORC实例分析》 1 JIT优化效果 create table t1(i int primary key, j int, k int); insert into t1…

Google IO 2024有哪些看点呢?

有了 24 小时前 OpenAI 用 GPT-4o 带来的炸场之后&#xff0c;今年的 Google I/O 还未开始&#xff0c;似乎就被架在了一个相当尴尬的地位&#xff0c;即使每个人都知道 Google 将发布足够多的新 AI 内容&#xff0c;但有了 GPT-4o 的珠玉在前&#xff0c;即使是 Google 也不得…

秋招算法——AcWing101——拦截导弹

文章目录 题目描述思路分析实现源码分析总结 题目描述 思路分析 目前是有一个笨办法&#xff0c;就是创建链表记录每一个最长下降子序列所对应的节点的链接&#xff0c;然后逐个记录所有结点的访问情况&#xff0c;直接所有节点都被访问过。这个方法不是很好&#xff0c;因为需…

消防物资存储|基于SSM+vue的消防物资存储系统的设计与实现(源码+数据库+文档)

消防物资存储系统 目录 基于SSM&#xff0b;vue的消防物资存储系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1用户功能模块 2 管理员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介…

动规解决01背包/完全背包精讲

还不会用动态规划解决01背包/完全背包&#xff1f;看这一篇文章就够了&#xff01; 首先我们要明白什么是01背包和完全背包。 背包问题总体问法就是&#xff1a; 你有一个背包&#xff0c;最多能容纳的体积是V。 现在有n个物品&#xff0c;第i个物品的体积为vi​ ,价值为wi​…

干货教程【AI篇】| Topaz Video Enhance AI超好用的视频变清晰变流畅的AI工具,免费本地使用

关注文章底部公众号&#xff0c;回复关键词【tvea】即可获取Topaz Video Enhance AI。 一款非常好用的视频变清晰变流畅的AI工具&#xff0c;即提高视频的分辨率和FPS&#xff0c;亲测效果非常nice&#xff01;&#xff01; 免费&#xff01;免费&#xff01;免费&#xff01…

【案例】使用Vue实现标题项元素上下移动

效果图 效果说明 每一组数据只能在对应的二级类目中进行上下移动&#xff0c;当点击上移图标的时候【左边的】会将当前元素与上一个元素交换位置&#xff0c;当点击的元素为该组的第一个元素时&#xff0c;将提示已经是第一项了并且不能进行移动&#xff1b;当点击下移图标的时…

Linux|如何允许 awk 使用 Shell 变量

引言 当我们编写 shell 脚本时&#xff0c;我们通常会在脚本中包含其他较小的程序或命令&#xff0c;例如 awk 操作。就 Awk 而言&#xff0c;我们必须找到将一些值从 shell 传递到 Awk 操作的方法。 这可以通过在 Awk 命令中使用 shell 变量来完成&#xff0c;在本文中&#x…