C语言底层知识------文件操作

简介: 本文详细介绍了文件操作的基本概念,包括文件的分类(程序文件和数据文件,其中着重于数据文件的文本文件和二进制文件),流的概念及其在C程序中的应用,以及标准输入输出流stdin、stdout和stderr的作用。作者通过示例展示了如何使用fopen、fclose和常见的读写函数如fgetc、fputc和fgets进行文件操作。

清明第二天,为了假期不这么放纵,现在又来更新一篇文件操作的文章,关于文件操作比较底层,这里我们就了解一下有关函数使用和一些基础概念即可,无需深究函数是如何实现。


文件的分类

相信文件大家都很清楚,对于电脑上我们都储存了许多地文件,但是文件还分两种类型,那分为哪两种呢?-------程序文件数据文件

程序文件


程序文件包括源程序文件(后缀为.c),目标⽂件(windows环境后缀为.obj),可执行程序(windows 环境后缀为.exe)。


数据文件


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


那么今天我们重点要讲的是数据文件唔。


那么其实数据文件还是可以细分为,文本文件,和二进制文件


二进制文件:在内存中数据以二进制储存,如果不加转换就直接输出到外存那就是二进制文件。


注意:二进制文件我们不编译打开的话我们是看不懂的。


文本文件:就与二进制文件相反,将内存中的二进制数据转化,再储存那就是文本文件,文本文件我们是可以看的懂的。

流的概念

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


大家可以把流当作一张银行卡,我们存钱时往里面塞钱,取钱也是从里面取,这就类似于我们对输入输出的需求,它是一个媒介,流也分种类,类似银行卡也有种类。

标准流


大家看到上面的描述是不是开始疑惑一个点了,既然我们输出和输入数据都需要打开流那自己在编程软件的时候没打开也可以打印和读取数据,这不是矛盾了嘛?别急下面一一到来。


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


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


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

而在我们编译器中是默认打开这三个流的,所以我们使用printf,和scanf等函数时,是不需要我们自己打开这几个流的。这三个流的类型为 FILE*类型通常称为文件指针。


缓冲文件系统中,关键的概念是“⽂件类型指针”,简称“文件指针”。 每个被使用的⽂件都在内存中开辟了⼀个相应的文件信息区,用来存放文件的相关信息(如文件的名 字,文件状态及文件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系 统声明的,取名 FILE.

关于文件信息区我们取一个例子:

int main()
{
 
  FILE* p1;
  FILE* p2;
  FILE* p3;
 
 
  return 0;
}


如上我们定义了三个为文件指针,如果给他们赋值,他们就会指向三个不同文件信息区。如下图:

如上,文件指针可以间接找到文件。


文件的打开和关闭

这里我们需要了解两个函数

FILE * fopen ( const char * filename, const char * mode );
 
int fclose ( FILE * stream );

第一个为打开文件函数,第二个为关闭文件的函数,我们进行文件操作时都需要打开和关闭。这是几乎要绑定在一起的。


然后打开文件中mode为打开文件模式,下面就列出几个常用的打开模式。


有关文本文件


“r”(只读) 为了输⼊数据,打开⼀个已经存在的文本文件    ( 如果文本文件不存在则会出错)


“w”(只写) 为了输出数据,打开⼀个文本文件  ( 如果文本文件不存在则会创建这个文本文件)


“a”(追加) 向文本文件尾添加数据    (如果文本文件不存在则会创建这个文本文件)


有关二进制文件


“rb”(只读) 为了输⼊数据,打开⼀个已经存在的二进制文件    ( 如果二进制文件不存在则会出错)


“wb”(只写) 为了输出数据,打开⼀个二进制文件  ( 如果文本文件不存在则会创建这个二进制文件)


“ab”(追加) 向二进制文件尾添加数据    (如果文本文件不存在则会创建这个二进制文件)


接下来是一些读写函数:


函数        功能                        适用于


fgetc   字符输入函数         所有输⼊流


fputc   字符输出函数          所有输出流


fgets   文本行输入函数       所有输⼊流


fputs   文本行输出函数       所有输出流


fscanf   格式化输入函数      所有输⼊流


fprintf   格式化输出函数      所有输出流


fread    ⼆进制输入              文件


fwrite  ⼆进制输出               文件


接下来就给大家试试其中几个函数和打开模式功能:

“r”只读打开模式和fgetc函数:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
 
int main()
{
 
  FILE* p1=fopen("p1.txt","r");//以只读的方式打开文件
  if (p1 == NULL)
  {
    perror("fopen:");
        return ;
  }
  int ch =1;
  printf("该文本文件里面的内容为:");
  while ((ch = fgetc(p1)) != EOF)
  {
    printf("%c", ch);//打印里面的内容
 
  }
  printf("\n");
 
  fclose(p1);//关闭文件
 
  return 0;
}

在运行代码时我们需要先创建一个文件夹和往文件夹里写点东西,如下:


我们先是打开文件,如果打开失败就打印错误信息,并结束程序,如果打开成功则继续运行下面的代码。

然后我们便开始读文件,while循环中每个读取到的文件的字符放到ch里,并打印出来。如下:


”w“打开模式和fputc函数 :

int main()
{
 
  FILE* p2=fopen("p2.txt","w");//以只写的方式打开文件
  if (p2 == NULL)
  {
    perror("fopen:");
    return;
  }
  int ch =1;
  
  for(ch='a';ch<='z';ch++)
  {
    fputc(ch, p2);
 
  }
  printf("\n");
 
  fclose(p2);//关闭文件
 
  return 0;
}


这里我没有创建p2这个文件夹,但是”w“的打开模式会为我们自动创建

运行过后就多了一个p2的文件夹了。

打开里面所编辑的正是我们所需打印的东西,24个英文字母。


剩下的fputs,fgets,和二进制文件操作也类似这种操作。fputs则是写字符串,fgets则是读字符串。二进制操作也是将文本文件变成二进制文件。我这里就不一一列举完出来了。这里再简单示例一个fgets函数吧。

int main()
{
 
  FILE* p2=fopen("p2.txt","r");//以只读的方式打开文件
  if (p2 == NULL)
  {
    perror("fopen:");
    return;
  }
  char arr[24];
  
  
    fgets(arr, 5,p2);
 
  
  printf("%s\n",arr);
 
  fclose(p2);//关闭文件
 
  return 0;
}

fgets(arr, 5,p2);


这里的fgets(arr, 5,p2);,表示读取到p2里的5个字符放到arr里去,但大家可能会疑惑,不是5个嘛,怎么只打印出四个,那是因为它会为‘\0’留一个位置,所以只读取4个字符。


今天的文章就到这里了。文章也是花了两天的零散时间写完的。

常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

目录
相关文章
|
27天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
3天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
372 16
|
19天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
6天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
21天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
23天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2594 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
5天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
182 2
|
3天前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
105 65
|
7天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
333 2
|
23天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1580 17
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码