【C语言】详解文件操作


(零)引入

        终端是计算机系统中与用户进行交互的界面。

 

        在以往的程序中,我们通过终端用键盘输入数据,通过屏幕输出信息。

        但是,如果我们不想手动低效地输入数据,而是通过文件一次性高效输入;

        如果我们不想让数据丢失,而是把输出的数据存储到文件中时,

        就需要使用一种新的操作——文件操作。

零.1什么是文件?


        文件是计算机系统中的一种数据存储形式;

        如文本、图像、音频、视频等。


(一)文件 

1.1为什么使用文件?


        程序运行时,我们写的程序的数据  是存储在电脑的内存中;如果程序退出,内存会被操作系统回收,于是数据就丢失了;等再次运行程序,无法得到上次程序的数据的。

        如果要将数据进行持久化的保存,就要使用文件。

1.2文件的特点: 

        文件可以由应用程序创建、读取、编辑、删除,它们是计算机系统中存储和传输数据的基本单位;

        文件可以被命名并存储在计算机的存储介质中;

        文件还可以根据其格式和扩展名来区分不同类型的文件, 如.txt文件是纯文本文件。

1.2.1文件名


        

 

        文件名是用来标识和区分文件的名称。它是文件系统中文件的唯一标识符。

        文件名的作用是以便用户识别和引用。


文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
重点:在C源文件中引用文件名要注意用两个斜杠来转义为一个斜杠

转义字符:"   \\     ==     \   "

1.3文件的分类 


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

1.3.1程序文件

        程序文件是包含计算机程序代码的文件。


        例如:".c"文件表示C语言程序文件, ".java"文件表示Java程序文件, ".py"文件表示Python程序文件等等。

         但是,程序文件不是我们要深入讨论的文件,因为我们是在程序文件中写代码,而进行文件操作需要的文件不是程序文件,而是数据文件。

1.3.2数据文件


        文件的内容不⼀定是程序代码,也可以是程序运行时读写的数据,比如一些文件在程序运行时被程序读取,同时接收并存储程序输出的数据 —— 这些提供输入数据和接受输出数据的文件就是数据文件。


        我们之前 所处理数据的输入输出都是以终端为对象的,即从终端的键盘输⼊数据,运行结果从终端显示到显示器(屏幕)上。


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


1.3.2.1 二进制文件和文本文件?


        根据数据的组织形式,数据文件被称为文本文件或者二进制文件。


        数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

        通常情况下,我们无法阅读二进制文件


        如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是文本文件。

如何形象理解二进制文件与文本文件呢?

        假如我们将10000 , ‘a’   等存入内存中,那么他在内存中是怎么存储的呢?

        对于字符,由于有ASCII表的存在,无论是二进制形式,还是文本形式,都是一样的;

        对于数字,就有所不同了,以10000为例,看一看他在内存中是怎么存储的呢?

例子:

        当以ASCII形式:每一个位都需要一个字节,需要5个字节;

        当以二进制形式:10000默认是整形,只需要4个字节。

数字在内存中的存储还是有很大不同的。


  到这里,我们理一下思路——>

小结:

 


(二)文件的打开和关闭

         为了更好的讲解文件操作,我们先要引入“流”的概念;

2.1什么是“流”


        我们的程序存在的意义就是处理问题,也就是说:

        需要程序从外部获取信息,经过处理之后输出信息。但是不同的设备输入信息的渠道是不同的,为了方便程序从外部获取信息,并且输出信息,C语言抽象出流的概念。


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


2.1.1标准流


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


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


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


• stdout-标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中。

————————标准输入输出流,说白了就是键盘和屏幕。


• stderr-标准错误流,⼤多数环境中输出到显⽰器界⾯。


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


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


        C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。


2.2文件指针

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

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

例如,VS2013提供的 <stdio.h> 头⽂件中有以上的⽂件类型申明:

        不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。

        每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信息,使⽤者不必关⼼细节。

        这个结构体储存了文件的关键信息,我们通过对结构体内对象的操作,间接实现对文件的操作:


2.3文件的打开和关闭


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


        使用fopen函数打开文件,在打开⽂件的同时,会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的关系。


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

//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );

文件的打开有多种方式,mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:

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

        “r” “w” “a” 是三个基本的打开方式—— 只写“r” “w” “a”表示打开文本文件, “rb” “wb” “ab”表示打开二进制文件。

         “r+” “w+” “a+”         “rb+” “wb+” “ab+”是复合的操作,是同时能够读和写的打开方式。


 

2.4文件的读写

        文件的读写有两种类型:顺序读写与随机读写 

对于顺序读写,C语言提供了标准库函数,他们包含在<stdio.h>中。

 

顺序读写函数介绍

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

从这些函数声明中,我们就能大致了解这些函数的使用方法了; 

 

 

 

 

 

 

 如果想要进一步深入了解,请看Cplusplus.com

(stdio.h) - C++ Reference (cplusplus.com)icon-default.png?t=N7T8https://legacy.cplusplus.com/reference/cstdio/


文件的打开方式是前提,读写是操作,文件关闭是习惯,指针置空是与人拉开的差距。

 

        上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);所有输出流⼀般指适⽤于标准输出流和其他输出流(如⽂件输出流)

        为了便于理解,这里给出一些应用实例:

#include<stdio.h>
#include<stdlib.h>

struct re_col
{
	char name[20];
	char us_n[20];
	char us_s[20];
	int age;
};

typedef struct re_col R;

int main()
{
	printf("请输入注册信息>用户名-账号-密码-年龄\n");
	
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","w");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	R* p = (R*)malloc(sizeof(R)*1);
	if(p == NULL)
	{
		perror("malloc");
		return 1;
	}
	
	scanf("%s%s%s%d",p->name,p->us_n,p->us_s,&(p->age));
	
	fprintf(pf,"%s %s %s %d",p->name,p->us_n,p->us_s,p->age);
	
	fclose(pf);
	pf = NULL;
	
	free(p);
	p = NULL;
	
	return 0;
}

         根据输入,把信息存放到文件 register collum 中;

#include<stdio.h>
int main1()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","r");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	int ch = fgetc(pf);
	
	if(feof(pf))
	{
		puts("EOF had been reached");
	}
	else if(ferror(pf))
	{
		puts("read failure");
	}
	printf("%d",ch);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

int main2()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","aw");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	fputs("iiiii\n",pf);
	fclose(pf);
	pf = NULL;
	
	return 0;
}

int main3()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","a");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs("abni",pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

int main4()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","r");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	char str[50] = {0};
	fgets(str,6,pf);
	fprintf(stdout,"%s\n",str);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

int main5()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","aw");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs("watink",pf);
	
	fclose(pf);
	pf = NULL;
	
	return 0;
}

int main6()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","r");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	char str1[50];
	
	fscanf(pf,"%s",str1);
	printf("%s\n",str1);//检验是否读取成功
	
	fclose(pf);
	pf = NULL;
	return 0;
}

int main7()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\register collum","w");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fprintf(pf,"abcded\n");
	fclose(pf);
	pf = NULL;
	return 0;
}

int main()
{
	FILE* pf1 = fopen("C:\\Users\\35587\\Desktop\\register collum","r");
	if(pf1 == NULL)
	{
		perror("fopen_1");
		return 1;
	}
	FILE* pf2 = fopen("data_copy.txt","w");
	if(pf2 == NULL)
	{
		fclose(pf1);
		pf1 = NULL;
		perror("fopen_2");
		return 1;
	}
	//op
	char ch;
	while((ch = fgetc(pf1)) != EOF)
	{
		fputc(ch,pf2);
	}
	
	fclose(pf1);
	pf1 = NULL;
	fclose(pf2);
	pf2 = NULL;
	return 0;
}

 



2.5⽂件的随机读写

        随机读写,实际意义是我们可以控制读写的位置,而不是真的“随机”。 


fseek


根据⽂件指针的位置和偏移量来 定位 ⽂件指针。


ftell


返回⽂件指针相对于起始位置的偏移量


rewind


让⽂件指针的位置回到⽂件的起始位置


 对rewind的应用实例:


int main()
{
	FILE* pf = fopen("C:\\Users\\35587\\Desktop\\data.txt","a+");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	char str[50];
	fgets(str,6,pf);
	printf("%s\n",str);
	int c = ftell(pf);
	printf("%d\n",c);
	rewind(pf);//回到起始位置

	fputs("acccsffe\n",pf);
	int c1 = ftell(pf);
	printf("%d\n",c1);
	
	fclose(pf);
	pf = NULL;
	
	return 0;
}

 

完~
 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络基础3

NAT&#xff08;Network Address Translation&#xff09;&#xff1a;网络地址转换 通过将内部网络的私有IP地址装换成全球唯一的公网IP地址&#xff0c;使内部网络可以连接到互联网。 广域网就是外网&#xff0c;局域网就是内网 私有IP地址&#xff1a;&#xff08;如果是纯内…

【MyBatis-Plus】简化你的Java持久层开发

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于MyBatis-Plus的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.MyBatis-Plus是什么 二.MyBati…

深入解析 Spring 和 Spring Boot 的区别

目录 引言 1. 设计理念 1.1 Spring 框架的设计理念 1.2 Spring Boot 的设计理念 2. 项目配置 2.1 Spring 框架的项目配置 2.2 Spring Boot 的项目配置 3. 自动配置 3.1 Spring 框架的自动配置 3.2 Spring Boot 的自动配置 4. 微服务支持 4.1 Spring 框架的微服务支持…

《工程数值计算Python教程》笔记

文章目录 [toc]第一章&#xff1a;绪论 1.1 1.1 1.1|数值计算在工程科学中的重要性 1.2 1.2 1.2|数值计算方法 1.3 1.3 1.3|程序设计盒图计算方法的选取减少运算次数避免相近的数相减 1.4 1.4 1.4|误差的来源、表示及传递误差的来源和分类模型误差观测误差截断误差舍入误差 误差…

【Java代码审计】目录穿越篇

【Java代码审计】目录穿越篇 1.Java中的目录穿越2.目录穿越漏洞审计3.Java中目录穿越漏洞修复 1.Java中的目录穿越 目录穿越漏洞产生的本质是路径可控&#xff0c;一旦涉及文件的读取问题便会涉及java.io.File类&#xff0c;因此在审计这类漏洞时可以优先查找java.io.File引用…

C++初阶-list类的模拟实现

list类的模拟实现 一、基本框架1.1 节点类1.2 迭代器类1.3 list类 二、构造函数和析构函数2.1 构造函数2.2 析构函数 三、operator的重载和拷贝构造3.1 operator的重载3.2 拷贝构造 四、迭代器的实现4.1 迭代器类中的各种操作4.1 list类中的迭代器 五、list的增容和删除5.1 尾插…

爬虫工作量由小到大的思维转变---<第十一章 Scrapy之sqlalchemy模版和改造(番外)>

前言: 正常的pymysql当然问题不大,但是我个人还是建议:sqlalchemy! 因为他更能让我们把精力放在表单设计上,而不执着于代码本身了. (-----版权所有。未经作者书面同意&#xff0c;不得转载或用于任何商业用途!----) 正文: 先提供一个基础模版: 表图: 创建表的sql: CREA…

软件设计师——法律法规(三)

&#x1f4d1;前言 本文主要是【法律法规】——软件设计师——法律法规的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304…

《科技风》期刊发表投稿方式、收稿方向

《科技风》杂志是经国家新闻出版总署批准&#xff0c;河北省科学技术协会主管&#xff0c;河北省科技咨询服务中心主办的国内公开发行的大型综合类科技期刊。 该刊集科技性、前瞻性、创新性和专业性于一体&#xff0c;始终以“把脉科技创新 引领发展风尚”为办刊宗旨&#xff…

ES-脚本

脚本 简单使用 POST product/_update/2 {"script": {"source": "ctx._source.salary1" #将薪水字段的值 1} }预定义变量 POST product/_update/2 {"script": {"lang": "painless","source": "…

Android studio中文汉化教程

相比于jetbrains的软件直接在软件内搜索chinese 就可以找到中文包相比&#xff0c;Android studio需要手动安装&#xff0c;接下来就给大家介绍下如何汉化 一、确认版本号 根据版本下载对应的中文汉化包&#xff0c;如果安装的汉化包版本不对应&#xff0c;可能会导致安装失败。…

升华 RabbitMQ:解锁一致性哈希交换机的奥秘【RabbitMQ 十】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 升华 RabbitMQ&#xff1a;解锁一致性哈希交换机的奥秘【RabbitMQ 十】 前言第一&#xff1a;该插件需求为什么需要一种更智能的消息路由方式&#xff1f;一致性哈希的基本概念&#xff1a; 第二&…

大华 DSS 数字监控系统 itcBulletin SQL 注入漏洞复现

0x01 产品简介 大华 DSS 数字监控系统是大华开发的一款安防视频监控系统,拥有实时监视、云台操作、录像回放、报警处理、设备管理等功能。 0x02 漏洞概述 大华 DSS存在SQL注入漏洞,攻击者 /portal/services/itcBulletin 路由发送特殊构造的数据包,利用报错注入获取数据库…

WPF-UI HandyControl 控件简单实战

文章目录 前言UserControl简单使用新建项目直接新建项目初始化UserControlGeometry:矢量图形额外Icon导入最优解决方案 按钮Button切换按钮ToggleButton默认按钮图片可切换按钮加载按钮切换按钮 单选按钮和复选按钮没有太大特点&#xff0c;就不展开写了总结 DataGrid数据表格G…

【机器学习】044_Kaggle房价预测(机器学习模型实战)

参考自《动手学深度学习》中“Kaggle比赛实战&#xff1a;预测房价”一节 一、数据准备 首先从网站上下载要获取的房价数据。 DATA_HUB是一个字典&#xff0c;用来将数据集名称的字符串和数据集相关的二元组一一对应。 二元组包含两个值&#xff1a;数据集的URL和用来验证文…

基于linux系统的Tomcat+Mysql+Jdk环境搭建(二)jdk1.8 linux 上传到MobaXterm 工具的已有session里

【JDK安装】 1.首先下载一个JDK版本 官网地址&#xff1a;http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载1.8版本&#xff0c;用红框标注出来了&#xff1a; 也许有的同学看到没有1.8版本&#xff0c;你可以随便下载一个linux的…

本地运行大语言模型并可视化(Ollama+big-AGI方案)

目前有两种方案支持本地部署&#xff0c;两种方案都是基于llamacpp。其中 Ollama 目前只支持 Mac&#xff0c;LM Studio目前支持 Mac 和 Windows。 LM Studio&#xff1a;https://lmstudio.ai/ Ollama&#xff1a;https://ollama.ai/download 本文以 Ollama 为例 step1 首先下…

限流常用算法以及基于Sentinel的微服务限流及熔断

一、服务限流的作用及实现 在没有任何保护机制的情况下&#xff0c;如果所有的流量都进入服务器&#xff0c;很可能造成服务器宕机导致整个系统不可用&#xff0c;从而造成巨大的损失。为了保证系统在这些场景中仍然能够稳定运行&#xff0c;就需要采取一定的系统保护策略&…

智能优化算法应用:基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于天牛须算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.天牛须算法4.实验参数设定5.算法结果6.参考文…

Ubuntu 常用命令之 ls 命令用法介绍

Ubuntu ls 命令用法介绍 ls是Linux系统下的一个基本命令&#xff0c;用于列出目录中的文件和子目录。它有许多选项可以用来改变列出的内容和格式。 以下是一些基本的ls命令选项 -l&#xff1a;以长格式列出文件&#xff0c;包括文件类型、权限、链接数、所有者、组、大小、最…