C语言入门篇——文件操作篇

news2025/2/28 3:16:48

目录

1、为什么使用文件

2、什么是文件

2.1程序文件

2.2数据文件

2.3文件名

3、文件的打开和关闭

3.1文件指针

3.2文件的打开和关闭

4、文件的顺序读写

5、文件的随机读写

5.1fseek

5.2ftell

5.3rewind

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

7、文件读取结束的判定

8、文件缓冲区


1、为什么使用文件

程序的数据是存放在内存中,当程序退出的时候,程序的数据自然就不存在了,等下一次运行我们的程序就需要重新输入自己的数据,这样就比较麻烦。数据持久化的方法一般有:吧数据存放在错案文件和存放到数据库等方式,我们使用文件的时候就可以把数据直接存放到电脑的硬盘上,做到了数据了持久化。

2、什么是文件

文件(file)通常是在磁盘或固态硬盘上的一段已命名的存储区。对我 们而言,stdio.h就是一个文件的名称,该文件中包含一些有用的信息。然 而,对操作系统而言,文件更复杂一些。例如,大型文件会被分开储存,或 者包含一些额外的数据,方便操作系统确定文件的种类。然而,这都是操作 系统所关心的,程序员关心的是C程序如何处理文件。

C把文件看作是一系列连续的字节,每个字节都能被单独读取。C提供两种文件模式:文本模式和二进制模式。

要区分文本内容和二进制内容、文本文件格式和二进制文件格 式,以及文件的文本模式和二进制模式。

所有文件的内容都以二进制形式(0或1)储存。但是,如果文件最初使用二进制编码的字符表示文本,该文件就是文本文件,其中包含文本内容。如果文件中的二进制值代表机器语言代码或数值数据或图片或音乐编码,该文件就是二进制文件,其中包含二进制内容。

为了规范文本文件的处理,C 提供两种访问文件的途径:二进制模式和 文本模式。在二进制模式中,程序可以访问文件的每个字节。而在文本模式 中,程序所见的内容和文件的实际内容不同。程序以文本模式读取文件时, 把本地环境表示的行末尾或文件结尾映射为C模式。

除了以文本模式读写文本文件,还能以二进制模式读写文本文件。

在程序设计中,我们一般谈的文件有两种:程序文件、数据文件。

2.1程序文件

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

2.2数据文件

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

2.3文件名

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

文件名包含3部分:文件路径+文件名主干+文件后缀,例如:D:\资料\vs\test

为了方便起见,文件标识常被称为文件名。

3、文件的打开和关闭

3.1文件指针

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

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 = NULL;

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

3.2文件的打开和关闭

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

//打开文件
FILE* fopen(const char* filename,const char* mode);
函数作用:打开文件
参数:filename:文件名
    mode:文件使用方式
返回值:成功:文件流指针
        失败:NULL

//关闭文件
int fclose(FILE* stream);
函数作用:关闭文件
参数:stream:文件指针流
返回值:成功:0
        失败:EOF(-1)
文件打开方式
文件使用方式含义如果至指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据建立一个新的文件
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建议一个新的文件建立一个新的文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

 

4、文件的顺序读写

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

 这里介绍fscanf,fprintf,fread,fwite四个函数。

fscanf() 和 fprintf() 函数与前面使用的 scanf() 和 printf() 功能相似,都是格式化读写函数,两者的区别在于 fscanf() 和 fprintf() 的读写对象不是键盘和显示器,而是磁盘文件。

函数原型如下:
int fscanf ( FILE *fp, char * format, ... );
int fprintf ( FILE *fp, char * format, ... );

函数参数:
fp 为文件指针;
format 为格式控制字符串;
... 表示参数列表;

fprintf() 返回成功写入的字符的个数,失败则返回负数
fscanf() 返回参数列表中被成功赋值的参数个数

与 scanf() 和 printf() 相比,它们仅仅多了一个 fp 参数

 两个函数的测试代码为:

int main(void)
{
	FILE* pf1 = NULL;
	pf1 = fopen("test.txt", "w");
	if (pf1 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char buf[1024] = "helloworld!";
	fprintf(pf1, "%s", buf);
	fclose(pf1);

	return 0;
}

int main(void)
{
	FILE* pf2 = NULL;

	pf2 = fopen("test.txt", "r");
	if (pf2 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char data[1024] = { 0 };
	int ret = fscanf(pf2, "%s", data);

	printf("ret:%d\n", ret);

	printf("data:%s\n", data);
	fclose(pf2);
	return 0;
}

 

 fread() 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制。fread() 的原型为:

size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );

 fwrite() 函数用来向文件中写入块数据,它的原型为:

size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );

 对参数的说明:

  • ptr 为内存区块的指针,它可以是数组、变量、结构体等。fread() 中的 ptr 用来存放读取到的数据,fwrite() 中的 ptr 用来存放要写入的数据。
  • size:表示每个数据块的字节数。
  • count:表示要读写的数据块的块数。
  • fp:表示文件指针。
  • 理论上,每次读写 size*count 个字节的数据。

size_t 是在 stdio.h 和 stdlib.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。

返回值:返回成功读写的块数,也即 count。如果返回值小于 count:

  • 对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
  • 对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测。

这两个函数的测试代码如下:

int main(void)
{
	FILE* pf1 = NULL;
	pf1 = fopen("test1.txt", "wb+");
	if (pf1 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char buf[1024] = { "hadhasio" };
	fwrite(buf, sizeof(buf), 1, pf1);
	fclose(pf1);

	return 0;
}

int main(void)
{
	FILE* pf2 = NULL;

	pf2 = fopen("test1.txt", "rb+");
	if (pf2 == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}

	char data[1024] = { 0 };
	int ret = fread(data, sizeof(data), 1, pf2);

	printf("ret:%d\n", ret);

	printf("data:%s\n", data);
	fclose(pf2);
	return 0;
}

5、文件的随机读写

5.1fseek

函数功能是把文件指针指向文件的开头,需要包含头文件stdio.h

函数原型:
int fseek(FILE *stream, long int offset, int whence)

参数:stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流
    offset -- 这是相对 whence 的偏移量,以字节为单位
    whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:

返回值:
如果成功,则该函数返回零,否则返回非零值。
常量描述
SEEK_SET文件的开头
SEEK_CUR文件指针的当前位置
SEEK_END文件的末尾

 测试代码如下:

int main()
{
	FILE* fp = NULL;

	fp = fopen("test.txt", "w+");
	if (fp == NULL)
	{
		printf("打开文件失败\n");
		return -1;
	}
	fputs("This is sakura0908", fp);

	fseek(fp, 7, SEEK_SET);
	fputs(" C Programming Langauge", fp);

	fclose(fp);

	return(0);
}

5.2ftell

返回给定流 stream 的当前文件位置,需要包含头文件stdio.h

函数原型:
long int ftell(FILE *stream);

参数:stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流

返回值:该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值

测试代码案例如下:

int main()
{
    FILE* fp = NULL;
    int len;

    fp = fopen("test.txt", "r");
    if (fp == NULL)
    {
        perror("打开文件错误");
        return(-1);
    }
    fseek(fp, 0, SEEK_END);

    len = ftell(fp);
    fclose(fp);

    printf("test.txt 的总大小 = %d 字节\n", len);

    return(0);
}

5.3rewind

设置文件位置为给定流 stream 的文件的开头,需要包含头文件stdio.h

函数原型:
void rewind(FILE *stream);

参数:
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流

返回值:
该函数不返回任何值

 测试代码案例如下:

int main()
{
   char str[] = "This is runoob.com";
   FILE *fp;
   int ch;

   /* 首先让我们在文件中写入一些内容 */
   fp = fopen( "file.txt" , "w" );
   fwrite(str , 1 , sizeof(str) , fp );
   fclose(fp);

   fp = fopen( "file.txt" , "r" );
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
   }
   rewind(fp);
   printf("\n");
   while(1)
   {
      ch = fgetc(fp);
      if( feof(fp) )
      {
          break ;
      }
      printf("%c", ch);
     
   }
   fclose(fp);

   return(0);
}

 

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

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。 数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文 本文件。 一个数据在内存中是怎么存储的呢? 字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而 二进制形式输出,则在磁盘上只占4个字节(VS2022测试)。

测试代码:

int main()
{
     int a = 10000;
     FILE* pf = fopen("test.txt", "wb");
     fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
     fclose(pf);
     pf = NULL;
     return 0;
}

7、文件读取结束的判定

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。

而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

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

例如: fgetc 判断是否为 EOF 或 fgets 判断返回值是否为 NULL .

2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

例如: fread判断返回值是否小于实际要读的个数。

int main(void)
{
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if (fp == NULL) 
    {
        perror("File opening failed");
        return -1;
    }
    //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
    {
        putchar(c);
    }

    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);

    return 0;
}

8、文件缓冲区

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

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

fflush函数:刷新缓冲区,某些编译器不支持,vs2022是不支持的。

fclsoe函数:关闭文件的时候,也会刷新缓冲区。

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

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

相关文章

玩转肺癌目标检测数据集Lung-PET-CT-Dx ——④转换成PASCAL VOC格式数据集

文章目录 关于PASCAL VOC数据集目录结构 ①创建VOC数据集的几个相关目录XML文件的形式 ②读取dcm文件与xml文件的配对关系③创建VOC格式数据集④创建训练、验证集 本文所用代码见文末Github链接。 关于PASCAL VOC数据集 pascal voc数据集是关于计算机视觉,业内广泛…

【五一创作】Pytroch nn.Unfold() 与 nn.Fold()图码详解

文章目录 Unfold()与Fold()的用途nn.Unfold()Unfold()与Fold() 变化模式图解 nn.Fold()单通道 滑动窗口无重叠模拟图片数据(b,3,9,9),通道数 C 为3,滑动窗口无重叠。单通道 滑动窗口有重叠。 卷积等价于:Unfold Matri…

Hadoop 2:MapReduce

理解MapReduce思想 MapReduce的思想核心是“先分再合,分而治之”。 所谓“分而治之”就是把一个复杂的问题,按照一定的“分解”方法分为等价的规模较小的若干部分,然后逐个解决,分别找出各部分的结果,然后把各部分的结…

从C语言到C++④(第二章_类和对象_上篇)->类->封装->this指针

目录 1. 面向对象 1.1 类的引入 1.2 class 关键字 2. 类的访问限定符及封装 2.1 访问限定符 2.2 封装 2.2.2 封装的本质 3. 类的作用域和实例化 3.1 类定义的两种方式 3.2 类的作用域 3.3 类的实例化 3.3.1 声明和定义的区别 4. 类对象模型 4.1 计算类的存储大小…

Java开发者在Windows环境安装各类开发工具汇总

Java开发者在Windows环境安装各类开发工具汇总 前言Java JDK下载配置 Tomcat下载配置 Maven下载配置配置仓库 Nginx下载启动关闭 MySQL下载配置my.ini初始化MySQL数据文件安装MySQL服务启动MySQL登录MySQL重置登录密码 NodeJs下载安装与验证配置NPM Git下载配置git配置ssh免密登…

Oracle删除列操作:逻辑删除和物理删除

概念 逻辑删除:逻辑删除并不是真正的删除,而是将表中列所对应的状态字段(status)做修改操作,实际上并未删除目标列数据或恢复这些列占用的磁盘空间。比如0是未删除,1是删除。在逻辑上数据是被删除了&#…

【MATLAB数据处理实用案例详解(22)】——基于BP神经网络的PID参数整定

目录 一、问题描述二、算法仿真2.1 BP_PID参数整定初始化2.2 优化PID2.3 绘制图像 三、运行结果四、完整程序 一、问题描述 基于BP神经网络的PID控制的系统结构如下图所示: 考虑仿真对象,输入为r(k)1.0,输入层为4,隐藏层为5&…

04-Vue技术栈之组件化编程

目录 1、模块与组件、模块化与组件化1.1 模块1.2 组件1.3 模块化1.4 组件化1.5 传统方式编写应用1.6 组件方式编写应用 2、非单文件组件2.1 基本使用2.2 几个注意点2.3 组件的嵌套2.4 VueComponent2.5 一个重要的内置关系2.6 总结 3、单文件组件3.1 一个.vue 文件的组成(3 个部…

常用排序算法汇总—Python版

一、选择排序 1. 原理: 选择排序(Selection Sort)是一种简单直观的排序算法,它的基本思路是将数组按顺序分成已排序部分和未排序部分,然后每次从未排序部分中选择出最小的元素,将其添加到已排序部分的末尾…

计算机网络|第三章:传输层

前文回顾:第二章:应用层 目录 📚概述和运输层服务 🐇运输层和网络层的关系 🐇因特网传输概述 📚多路复用和多路分解 🐇无连接的多路复用与多路分解 🐇面向连接的多路复用与多路…

【硬件】嵌入式电子设计基础之分析电路

电子技术(electronics)是我们研究科技产品的基石,本文章通过一系列简单且使用的实例,带领大家走进电子技术的世界,并通过对这些实例的分析,掌握其中的知识点和实用的电路分析设计技能。 本篇文章围绕着模拟…

三数之和(Java实现)

文章目录 思路1.暴力算法(超出时间限制)解题思路复杂度 2.双指针算法解题思路&#xff1a;注意点复杂度 Problem: 15. 三数之和 思路 1.暴力算法 2.双指针算法 1.暴力算法(超出时间限制) class Solution {public List<List<Integer>> threeSum(int[] nums) {// 检查…

使用TrieTree(字典树)来实现敏感词过滤

使用TrieTree&#xff08;字典树&#xff09;来实现敏感词过滤 1. 字典树定义 字典树&#xff08;TrieTree&#xff09;&#xff0c;是一种树形结构&#xff0c;典型应用是用于统计&#xff0c;排序和保存大量的字符串&#xff08;但不仅限于字符串,如01字典树&#xff09;。…

Hive本地开发/学习环境配置

前提 hive依赖hadoop的相关组件&#xff0c;需要启动Hadoop的相关组件。 Hive 版本&#xff1a;3.1.3 Hadoop版本&#xff1a;3.3.4 hive-env.sh export HADOOP_HOME$HADOOP_HOME export HIVE_CONF_DIR/usr/local/Cellar/hive/3.1.3/libexec/conf export HIVE_AUX_JARS_PATH/…

micro-app的简单学习

本文承接上一篇手把手教你使用vue2搭建micro-app&#xff0c;对micro-app进行简单的认识与学习。 简述 因为上一篇只是对micro-app的搭建&#xff0c;并没有对具体的内容进行深入了解&#xff0c;所以本文是在上一篇文章代码的基础上对micro-app官网&#xff0c;的初步了解。…

Vue(标签属性:ref、配置项:props、混入mixin、插件、样式属性:scroped)

一、ref&#xff08;打标识&#xff09; 前面提及到了标签属性&#xff1a;keys 这里将了解ref&#xff1a;打标识 正常布置脚手架并创建入口文件main.js,引入组件 1. 可以给元素注册引用信息&#xff08;获取真实DOM&#xff09; 给一个按钮获取上方的dom的方法&#xff0c;方…

log4j2实现日志输出

引言 日志是我们在软件开发过程中非常重要的一个组成部分&#xff0c;它能够记录系统运行时的各种信息和异常&#xff0c;方便我们在需要的时候进行排查和调试。而Log4j2是目前最为流行的Java日志框架之一&#xff0c;它提供了丰富的日志输出方式和配置选项&#xff0c;可以满…

设计模式——装饰器模式(Decorator Pattern)

很久没有写博客了&#xff0c;最近也有很多事情要处理&#xff0c;也在努力的备考软件考试&#xff0c;正好模拟题中有一道关于装饰器模式的题&#xff0c;觉得还不错&#xff0c;所以特地写一篇文章希望能分享给小伙伴们。 装饰器模式的作用&#xff1a;允许向一个现有的对象…

vue3导入elcel表格并展示(使用xlsx插件+vite+element-plus)/js上传表格(js+xlsx)

表格内容(本博客演示的表格,这里其实可以更换任意表格,动态展示的) 安装插件xlsx npm install xlsx组件的所有代码(附解释) <script setup> import { ref } from "vue"; import * as XLSX from "xlsx"; // 把文件按照二进制进行读取 function read…

解密PyTorch动态计算图:打破深度学习束缚的秘密武器

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…