【C语言】详解文件操作

news2024/12/23 8:58:35


(零)引入

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

 

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

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

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

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

零.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.coloradmin.cn/o/1315847.html

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

相关文章

OpenHarmony 如何去除系统锁屏应用

前言 OpenHarmony源码版本&#xff1a;4.0release / 3.2 release 开发板&#xff1a;DAYU / rk3568 一、3.2版本去除锁屏应用 在源码根目录下&#xff1a;productdefine/common/inherit/rich.json 中删除screenlock_mgr组件的编译配置&#xff0c;在rich.json文件中搜索th…

GraphicsProfiler 使用教程

GraphicsProfiler 使用教程 1.工具简介&#xff1a;2.Navigation介绍2.1.打开安装好的Graphics Profiler。2.2.将手机连接到计算机&#xff0c;软件会在手机中安装一个GraphicsProfiler应用(该应用是无界面的&#xff09;。2.3.Show files list2.4.Record new trace2.4.1.Appli…

自然数分解 C语言xdoj64

输入说明 一个正整数 n&#xff0c;0<n<30 输出说明 输出n个连续奇数&#xff0c;数据之间用空格隔开&#xff0c;并换行 输入样例 4 输出样例 13 15 17 19 int main() {int n;scanf("%d",&n);if(n % 2 0){//n为偶数int in;//打印数字个数&#xff0c;做循…

【每日一题】统计区间中的整数数目

文章目录 Tag题目来源解题思路方法一&#xff1a;平衡二叉搜索树 写在最后 Tag 【平衡二叉搜索树】【设计类】【2023-12-16】 题目来源 2276. 统计区间中的整数数目 解题思路 方法一&#xff1a;平衡二叉搜索树 思路 用一棵平衡二叉搜索树维护插入的区间&#xff0c;树中的…

Java-----链表练习题(上)

本篇碎碎念&#xff1a;本篇无碎碎念 今日份励志文案: 很多人认为他们在思考&#xff0c;其实他们只是在整理自己的偏见 目录 一.203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 二.21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09…

【STM32入门】4.2对射红外传感器计次

1.接线方式 主要是编写传感器的驱动、配合OLED&#xff0c;每遮挡对射红外传感器&#xff0c;OLED屏幕的计数就加一。 2.驱动编写 首先新建.c文件和.h文件&#xff0c;命名为CountSensor 国际惯例&#xff0c;.c文件内要包含stm32.h头文件&#xff0c;然后编写 CountSensor_…

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 尾插…

力扣第2题-判断一个数值是否是回文数[简单]

题目描述 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff0c;121 是回文&am…

c语言中的static静态(1)static修饰局部变量

#include<stdio.h> void test() {static int i 1;i;printf("%d ", i); } int main() {int j 0;while (j < 5){test();j j 1;}return 0; } 在上面的代码中&#xff0c;static修饰局部变量。 当用static定义一个局部变量后&#xff0c;这时局部变量就是…

蓝桥杯专题-真题版含答案-【扑克牌排列】【放麦子】【纵横放火柴游戏】【顺时针螺旋填入】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

人工智能与量子计算:开启未知领域的智慧之旅

导言 人工智能与量子计算的结合是科技领域的一场创新盛宴&#xff0c;引领我们进入了探索未知领域的新时代。本文将深入研究人工智能与量子计算的交汇点&#xff0c;探讨其原理、应用以及对计算领域的深远影响。 量子计算的崛起为人工智能领域注入了新的活力&#xff0c;开启了…

认知能力测验,①如何破解数字推理类测试题?

校园招聘&#xff08;秋招春招&#xff09;&#xff0c;最为常见的认知能力测验&#xff0c;在线工具网将整理分析关于认知能力测验的系列文章&#xff0c;希望能帮助大家顺利通过认知能力测评&#xff0c;找到自己心仪的工作。 数字推理测试&#xff0c;是我们在求职中经常会…

汇编语言的前世今生

计算机中的0和1是用电的状态表示的。具体来说&#xff0c;断开为0&#xff0c;接通为1。自然而言&#xff0c;这也对应着二进制。曾经时代的二进制加法机是一个划时代的产物&#xff0c;能够进行两个8位二进制数的实时加法&#xff0c;尽管今天看来很LOW。 图1 二进制加法器&am…

面向对象三大特征之二:继承

继承的快速入门 什么是继承&#xff1f; Java中提供了一个关键字extends&#xff0c;用这个关键字&#xff0c;可以让一个类与另一个类建立起父子关系 继承的特点 子类能继承父类的非私有成员&#xff08;成员变量、成员方法&#xff09; 继承后对象的创建 子类的对象是由…

商用机器人,不好用是原罪

热潮褪去后&#xff0c;所有的问题都汇总成一个词&#xff0c;不好用。 从炙手可热到“大玩具” 一款产品好用与否&#xff0c;更多时候人们不会关心它先进的技术、工艺、用料&#xff0c;也不会考虑所谓的潮流趋势或前景&#xff0c;只会用最朴素的直观感受告诉你&#xff0…

TrustZone之总线请求

接下来&#xff0c;我们将查看系统中的总线请求者&#xff0c;如下图所示&#xff1a; 系统中的A型处理器具有TrustZone感知&#xff0c;并在每个总线访问中发送正确的安全状态。然而&#xff0c;大多数现代SoC还包含非处理器总线请求者&#xff0c;例如GPU和DMA控制器。 与完成…

Modbus转Profinet网关使用方法

Modbus转Profinet网关&#xff08;XD-MDPN100/200&#xff09;是用于将Modbus协议和Profinet协议进行转换并进行通迅的设备。Modbus转Profinet网关&#xff08;XD-MDPN100/200&#xff09;无论是新项目还是改造项目都可轻松配置完成通迅互联。 正确的安装和配置对于确保设备的正…

讨好型人格最适合从事什么职业?

讨好型人格&#xff0c;其言行不是考虑个人&#xff0c;而是以满足对方为主&#xff0c;只要是他人的想法&#xff0c;都会尽力去满足&#xff0c;特别害怕自己做了什么事情&#xff0c;让对方产生不满的想法。遇到事情&#xff0c;也很难主动请求别人&#xff0c;总是依靠自己…

Hudi 在 vivo 湖仓一体的落地实践

作者&#xff1a;vivo 互联网大数据团队 - Xu Yu 在增效降本的大背景下&#xff0c;vivo大数据基础团队引入Hudi组件为公司业务部门湖仓加速的场景进行赋能。主要应用在流批同源、实时链路优化及宽表拼接等业务场景。 一、Hudi 基础能力及相关概念介绍 1.1 流批同源能力 与H…

Caused by: java.net.ConnectException: 拒绝连接: hadoop104/192.168.124.130:4142

项目场景&#xff1a;hadoop102接收消息&#xff0c;自定义拦截器&#xff0c;包含hello的发往hadoop103,不包含的发往hadoop104 报错原因&#xff1a; 原因1&#xff1a; 应该先开启接收方&#xff08;服务端&#xff09;&#xff0c;hadoop103,hadoop104,最后开启hadoop10…