c语言文件操作(超详细)

前言

这次的博客,可以让大家快速掌握文件操作,方便大家快速找到不懂的内容

文件操作的作用以及基础

1. 为什么使用文件?

如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失 了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件

2. 什么是文件?

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

3.文件名

⼀个文件要有⼀个唯⼀的文件标识,以便用户识别和引用  文件名包含3部分:文件路径+文件名主干+文件后缀 例如: c:\code\test.txt 为了方便起见,文件标识常被称为文件名

4.⼆进制文件和文本文件

根据数据的组织形式,数据文件被称为文本文件或者⼆进制文件。 数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的文件中,就是⼆进制文件 。如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

5.流

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

6.标准流

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

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

• stdin - 标准输入流,在大多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。 • stdout - 标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中

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

这是默认打开了这三个流,我们使用scanf、printf等函数就可以直接进行输入输出操作的。 stdin、stdout、stderr 三个流的类型是: FILE * ,通常称为文件指针。 C语言中,就是通过 FILE* 的文件指针来维护流的各种操作的

7.文件指针

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

文件操作的使用

这里的讲解包括很多,慢慢来,前面的不懂没关系,我们直接看代码就好

文件的打开和关闭

我们使用fopen()函数打开 文件        使用fclose()关闭文件

再此之前可以看看他们的定义

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

int fclose( FILE *stream );

看看使用吧,

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

第一个参数是流,是一个文件指针 第二个参数是模式下面代码是"w"为只写模式

int main()
{
	FILE* pl= (FILE*)fopen("text.txt", "w");
	char a[20] = "hello world";
	char* p = a;
	while(*p!='\0')
	fputc(*p++,pl);
	fclose(pl);
	return 0;
}

在这里提醒一句,在只写模式中自能写入信息,不能读信息,待会还会在提醒,别急

看结果

绝对路径与相对路径

这个代码就是通过while循环,把一个字符串一个一个字符的存储在文件text.txt中

fopen的第一个参数为文件名其实在这里是相对路径,还可以使用绝对路径来作为参数

其实使用绝对路径更加严谨,因为相对路径是相对于本电脑而言的路径,绝对路径也不难,

可以从文件夹中复制出来,就拿刚刚生成的文件来试水

红方框所包的位置就是文件的绝对路径,其实很简单,找到文件,然后查看文件的属性

我们在把它写入代码中看看能否成功

但这里注意,位置给的是前面路径,最后还要加上自己的文件名

emmmm 失败了 为什么呢?

原因是转义字符,我们的 \t  \ddd 在这里d指的是数字呦 比如 \5 \6 \123 \24

这里是表示最少一位最多三位的8进制的数字

ok 我们现在在所有的转义字符中在多加入一个\就可以解决问题了

这样就成功了

文件的读写模式

我们就直接打出来把

其实这是由规律的,发现没

1 有后缀b就是二进制文件

2 r 读 w 写  a追加 记住就好 后缀+就是读写

3r只能读文件,一旦文件不存在 报错,但是w 和a可以创造文件 当它不存在时

4w(只写)每次打开文件时会把原文件的内容覆盖,然后重新写入

5 a追加 r 只读不会改变原有的文件,追加时是在原有的内容上追加的

最后大家要自行尝试各种模式下的文件操作

接下来要讲解一些相关的输入输出函数

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

int fgetc(FILE *pf);
int fputc(int n,FILE *pf);
char*fgets(const char *a,size_t num,FILE *pf);
char *fputs(const char *a,FILE * pf);
int fread(cosnt char *buf,size_t typesize,size_t elementnums,FILE* pf);
int fwrite(const char *buf,size_t typesize,size_t elementnums,FILE* pf)

单个字符处理函数

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

看代码

//fputc
int main()
{
	FILE* pf = fopen("BoKe.txt", "w");
	//1 fputc 针对文件流
	char a[20] = "djlkawj";
	char* p = "dkakdkla";
	for (int i = 0; i < strlen(a); i++)
	{
		fputc(a[i], pf);
	}
	//2fputc 针对屏幕(标准输出流)
	while (*p != '\0')
	{
		fputc(*p++, stdout);
	}
	fclose(pf);
}

看结果

看fgetc

int main()
{
	FILE* pf = fopen("BoKe.txt", "r");
	int ch = 0;
	//注意要打括号,赋值操作符的优先级小于逻辑操作符
	//遍历文件流所有内容
	//针对文件流
	while((ch = fgetc(pf))&&ch!=EOF)
	putchar(ch);
	fclose(pf);
	printf("\n");
	int a = 0;
	//针对标准输入流
	while ((ch = fgetc(stdin))&&ch!= EOF)
	{
		putchar(ch);
	}
	return 0;
}

行字符处理函数

char*fgets(const char *a,size_t num,FILE *pf);
char *fputs(const char *a,FILE * pf);

直接看代码

int main()
{
	//fputs 针对文件流
	FILE* pf = fopen("BoKe.txt", "w");
	char buffer[20] = "jdakldjad";
	fputs(buffer, pf);
	char buffer2[20] = "jdalkdajjadlk";
	fputs(buffer, pf);
	//针对 输出流
	fputs(buffer, stdout);
	fputs(buffer2, stdout);
	fclose(pf);
	//fgets 针对文件流
	pf = fopen("BoKe.txt", "r");
	char buffer3[20];
	fgets(buffer3, 10, pf);
	printf("%s\n", buffer3);
	//针对输出流
	char buffer4[20];
	fgets(buffer4, 10, stdin);
	printf("%s\n", buffer4);
	return 0;
}

看结果

值得注意的是在fgets中有一个限制大小的参数,该参数可以防止数组越界,并且注意的是在给数组值时该限制长度是字符串的长度

并且他不像gets puts一样可以自带换行,注意他不会自动换行

而且遇到换行不会结束,只有遇到\0或者文本结束符号ctrl+z才会结束

这个千万不要搞错了

格式化输入输出函数

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

int main()
{
	student s1 = { 20,"zhangsan",80 };
	FILE* pf = fopen("Test.txt", "w");
	fprintf(pf,"%d %s %d",s1.aag,s1.name,s1.score);
	fclose(pf);
	pf=fopen("Test.txt", "r");
	student s2 = { 0 };
	fscanf(pf, "%d %s %d", &(s2.aag), s2.name,&(s2.score));
	printf("%d %s %d\n", s2.aag, s2.name, s2.score);
	fclose(pf);
	pf=fopen("Test.txt", "wb");
	student arr[3] = { {20,"zhangsan",56},{25,"lisi",15},{65,"haha",99} };
	fwrite(arr, sizeof(student),3, pf);
	fclose(pf);
    return 0;
}

只针对文件流的输入输出

fread ⼆进制输入 文件输入流
fwrite ⼆进制输出 文件输出

我们仍然看上面的代码

此时文件中存储了,

student arr[3] = { {20,"zhangsan",56},{25,"lisi",15},{65,"haha",99} };

三个结构体成员,我们要取得最后一个结构体元素的内容怎么办

通过一个fseek()找到最后一个结构体元素的位置,也就是文件指针

的指向位置,在通过fread读出该结构体

当然 fwrite的使用就更加简单了,先看fseek和fread的联动

int main()
{
	FILE *pf = fopen("Test.txt", "rb");
	student s3 = { 0 };
	fseek(pf, -(long)sizeof(student), SEEK_END);
	fread(&s3, sizeof(student), 1, pf);
	printf("%d %s %d\n", s3.aag, s3.name, s3.score);
	return 0;
}

这个代码就是可以取出元素

看看fwrite

#include <stdio.h>
int main()
{
 int a = 10000;
 FILE* pf = fopen("test.txt", "wb");
 fwrite(&a, 4, 1, pf);//⼆进制的形式写到⽂件中
 fclose(pf);
 pf = NULL;
 return 0;
}

fread 和fwrite都一样

4个参数 第一个是要取或读的地址,第二个是类型所占的字节大小 第三个是文件流

而且必须是文件流

当然这里是一定是二进制的,fwrite 是把内容以二进制写入文件

fread是把内容读入一个被指向的地址中

总算结束了,希望有所帮助吧

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

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

相关文章

(arxiv2401) CrossMAE

作者团队来自加州大学伯克利分校&#xff08;UC Berkeley&#xff09;和加州大学旧金山分校&#xff08;UCSF&#xff09;。论文主要探讨了在MAE的解码中&#xff0c;图像patch之间的依赖性&#xff0c;并提出了一种新的预训练框架 CrossMAE。 论文的主要贡献包括&#xff1a; …

代码随想录-算法训练营day02【滑动窗口、螺旋矩阵】

专栏笔记&#xff1a;https://blog.csdn.net/weixin_44949135/category_10335122.html https://docs.qq.com/doc/DUGRwWXNOVEpyaVpG?uc71ed002e4554fee8c262b2a4a4935d8977.有序数组的平方 &#xff0c;209.长度最小的子数组 &#xff0c;59.螺旋矩阵II &#xff0c;总结 建议…

(源码+部署+讲解)基于Spring Boot和Vue的大学生快递代取服务平台的设计与实现

一、引言 本报告旨在详细阐述基于Spring Boot后端框架和Vue前端框架的大学生快递代取服务平台的设计与实现过程。该平台旨在为大学生提供便捷的快递代取服务&#xff0c;解决因时间冲突或距离过远而无法及时取件的问题。通过该平台&#xff0c;用户可以发布代取需求&#xff0c…

[中级]软考_软件设计_计算机组成与体系结构_07_存储系统

存储系统 层次划存储概念图局促性原理分类存储器位置存取方式按内容存储按地址存储 工作方式拓展 往年真题 高速缓存(cache)概念案例解析&#xff1a;求取平均时间 Cache与主存的地址映射映像往年真题 主存编制计算编址大小的求取编址与计算存储单元编址内容总容量求取例题解析…

java爬虫入门程序

<!--爬虫仅支持1.8版本的jdk--> <!-- 爬虫需要的依赖--> <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.2</version> </dependency><!-- 爬虫需…

github生成新的SSH密钥

首先是参考官方文档 生成新的 SSH 密钥并将其添加到 ssh-agent述 当你在创建SSH密钥时遇到提示&#xff1a; Enter file in which to save the key (/c/Users/YOU/.ssh/id_ALGORITHM):这一步是让你选择保存生成的SSH密钥对的文件名和位置。如果你直接按回车键&#xff08;[Pr…

Java项目:基于Springboot+vue实现的医院住院管理系统设计与实现(源码+数据库+开题报告+任务书+毕业论文)

一、项目简介 本项目是一套基于Springbootvue实现的医院住院管理系统设 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简…

Activity入门2——生命周期与任务栈

OnCreate与OnDestroy OnCreate&#xff1a;创建一个活动。 OnDestroy&#xff1a;销毁一个活动。 假设某个用户在一个活动里输入了一些信息&#xff0c;用户由于某些原因退出了该活动&#xff0c;返回时希望能够还原之前输入的信息&#xff0c;不然重新输入就太麻烦了。 pub…

软考高级架构师:嵌入式软件开发概念和例题

一、AI 讲解 嵌入式软件开发和传统软件开发的差异 嵌入式软件开发与传统软件开发在目标、环境和开发过程等方面有显著的差异。下面通过对比的方式&#xff0c;简要阐述这些差异所在&#xff1a; 特性嵌入式软件开发传统软件开发开发目标针对特定硬件系统&#xff0c;强调软硬…

【Fn+windows键】‘Windows键+L’不能锁屏的问题

winL锁屏 3个键盘灯1.NumLock指示灯2.CapsLock指示灯3.ScrollLock指示灯 2.电脑锁屏问题 突然发现winL不能锁屏&#xff0c;反而是在自己打开的软件界面内编辑 各种操作之下&#xff0c;发现键盘上最不常用的灯亮了 所以了解了一番键盘灯的功能 3个键盘灯 1.NumLock指示灯 N…

快递费用一目了然:taobao.item_fee API在电商中的应用

taobao.item_fee API在电商中的应用主要体现在精准计算快递费用&#xff0c;从而为用户提供一个更加透明和便捷的购物体验。这一接口允许淘宝或天猫的开发者根据商品ID、收货地址等信息&#xff0c;精确计算商品的快递费用。对于用户而言&#xff0c;这意味着在购物过程中能够实…

工厂模式图

工厂模式 介绍一下简单工厂模式与工厂方法模式 结构图 简单工厂模式 工厂方法模式

【剑指offr--C/C++】JZ7 重建二叉树

一、题目 二、思路及代码 前序遍历&#xff1a;中、左、右。所以前序遍历的第一个节点是树的根节点&#xff0c;第二个节点是左子树的根节点。。。。 中序遍历&#xff1a;左、中、右。树的根节点在中间某处 我们可以根据二者的特点结合一下&#xff1a;对于前序遍历序列{1,2,4…

ubuntu安装sublime3并设置中文

安装Sublime Text 3 在Ubuntu上安装Sublime Text 3可以通过以下步骤进行&#xff1a; 打开终端。 导入Sublime Text 3的GPG密钥&#xff1a; wget -qO- https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add - 添加Sublime Text 3的存储库&#xff1a; …

纯C代码模板

一、快排 void QuickSort(int *a,int left,int right){if(left>right) return;else{int low left,high right;int pivot a[low];while(low<high){while(a[high] > pivot && low < high){high--;}a[low] a[high]; //必须先动a[low]while(a[low] < …

TR3 - Transformer算法详解

目录 文本输入处理词向量位置向量 编码器 EncoderSelf-Attention多头注意力机制残差连接 解码器 Decoder线性层与Softmax损失函数总结与心得体会 这周来看一下Transformer是怎么将文本转换成向量&#xff0c;然后又输入到模型处理并得到最终的输出的。 文本输入处理 词向量 …

计算机内存是如何管理的

计算内存的那些事儿——内存管理 大家回忆一下&#xff0c;计算机结构&#xff0c;或者说一个SoC&#xff08;system-on-chip&#xff09;芯片的结构。 cpu、memory、peripherals&#xff0c;这是计算机的主要部件&#xff0c;三者之间通过system bus勾搭在一起。 The main co…

易支付和独角数卡对接TokenPay开通USDT收款教程

TRX、USDT-TRC20、ETH系列区块链代币的支付通道是很多发卡和电商平台需要的&#xff0c;因为传统的微信、支付宝、PayPal等支付接口审查严格、手续费高。自建的代币接口完成没有手续费&#xff0c;稳定可靠&#xff0c;也没有审查要求。 易支付在行业普及广泛&#xff0c;大部…

JVM(Java虚拟机)

文章目录 一、JVM简介1.1 JVM概念1.2 什么是Java虚拟机呢&#xff1f;Java虚拟机的好处是什么呢&#xff1f; 二、JVM整体组成部分三、类加载器3.1 类加载子系统3.2 类加载过程3.2.1 装载(Load)3.2.2 链接(Link)3.2.3 初始化(Initialize) 四、运行时数据区4.1 方法区&#xff0…

stack 与 queue 与 priority_queue 与 仿函数 与 模板进阶

目录 stack queue deque priority_queue 使用 模拟实现 仿函数 仿函数的用法 仿函数的意义 模板进阶 非类型模板参数 模板特化 类模板特化的用法 类模板特化的意义 函数模板特化的用法 模板的分离编译 模板分离编译报错的原因 ​解决方法 模板总结 栈、队列…