当前位置: 首页 > article >正文

编程之路,从0开始:文件操作(1)

        Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!

        今天我们来讲C语言的文件操作。通过这节课,我们来学习如何使用C语言提供的一系列文件操作。

目录

1、文件操作引入

2、流

3、文件指针

4、文件的打开与关闭

5、文件的顺序读写

(1)fgetc

(2)fputc

(3)fgets

(4)fputs

(5)fscanf

(6)fprintf

(7)fread

(8)fwrite


1、文件操作引入

        首先,我们要知道我们平时写的程序都是储存在内存中的,当结束程序后,我们的数据就消失了。所以为了长久的保存数据,我们可以使用文件来进行保存。

        我们平时写的程序文件都是以.c、.obj、.exe为结尾的,文件操作我们主要是将数据存入.txt文件或从.txt文件读取。

        在C语言中创建文件时,我们需要文件标识,并且一个文件只能有一个文件标识。通常,文件标识被称为文件名。


2、流

       不知道大家在之前有没有了解过流这个概念。

       其实,流就是为了从各种设备上读取数据,或者输出数据到设备上,而抽象出的一种概念。在这里我们可以简单理解为流淌着各种字符的河

        C语言默认打开三种流:标准输入流,标准输出流,标准错误流。

        我们常用的scanf标准输入流中读取数据,printf就是将信息输出到标准输出流中。


3、文件指针

        C语言FILE*文件指针用来维护流中的各种操作(这里且不深入讨论),我们在进行文件操作时必须要用到FILE*指针。

现在我们创建一个文件指针变量pf:

int main()
{
	FILE* pf;
	return 0;
}

        我们可以使文件指针变量pf指向某个文件的文件信息区,这样我们就可以通过文件指针变量pf简洁的找到和访问与他相关的文件。


4、文件的打开与关闭

        文件在读取之前应该先打开文件,在使用结束之后关闭文件。

        在编写程序的时候,打开文件的同时,都会返回一个FILE*指针变量指向该文件。

现在我们使用fopen打开文件,fclose关闭文件:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf=fopen("test.txt", "w");//打开文件
	if (pf != NULL)
	{
		//......
		//文件操作
		fclose(pf);//关闭文件
	}
	return 0;
}

        以上是一套完整的打开和关闭文件流程。

这是函数fopen的原型:

35263a8c362446f1aa85c2448aca311f.png

第一个参数我们以字符串形式将文件名传入,当然这里我们并没有这个文件,当打开文件后他会在这个项目所在的文件目录下创建这个文件。

cb3c5bf894814b21adaff0107c4eeab3.png

第二个参数我们以字符串形式把打开方式传入,以下是所有的打开方式

3b7bfccb912d4811ac0dc90eb8785bee.png实际上,我们常用的只有几个。

        我们再看文件关闭函数原型:

0277264841f44aaeb86c67303be496c4.png

我们将文件指针传入。就可以关闭这个文件指针指向的文件啦!


5、文件的顺序读写

        下面我们来介绍几个顺序读写函数。我们可以利用这几个函数进行文件操作。

(1)fgetc

cbda462a720c433bb47036f3a3cfd1a4.png        这个函数适用于所有输入流,是一个字符输入函数。

示例:

8e338789b2044f2fbb14e471edbf20af.png        注意,我们要用“r”只读的方式打开文件,如果用“w”的方式打开文件,他会更改我们的文件内容。

        我们想读取字符,所以我们先把test.txt文件中放上内容并保存:

aeb9dea15dc64440b1d37db49c6063b6.png        现在读取字符,他会从第一个字符位置读取。我们把他读取的字符传给c,并打印到控制台上:

a3bbf983cc2a4801ad80b5dac120d23a.png

现在我们对代码进行升级:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf=fopen("test.txt", "r");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		for (i = 0;i < 5;i++)
		{
			char c = fgetc(pf);
			printf("%c", c);
		}
		fclose(pf);//关闭文件
	}
	return 0;
}

打印结果:

c75b968d278d4b6e929bdfd70bc17f8a.png

        当每次读取完成后,光标后往后移动一位。这时候我们在进行读取操作,就会读取到下一个字符。我们利用这个特性,用循环嵌套进行读取,达到读取字符串的功能。但是由于我们只有三个字符,所以打印出来后两个位置是错误信息。

        另外有一点需要注意,fgetc在遇到空格时会选择跳过。


(2)fputc

        这个函数时字符输出函数,它适用于所有标准输出流。

9affb24673344e68a2f8c12a8872e0d2.png

        我们传入想写入的字符,在传入文件指针:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf=fopen("test.txt", "w");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		fputc('s', pf);//写入s
		fclose(pf);//关闭文件
	}
	return 0;
}

        现在我们打开test.txt发现他已经写入了字符s。

        但是需要注意,我们不能实现这串代码:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf=fopen("test.txt", "w");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		fputc('s', pf);//写入s
		char c = fgetc(pf);//读取s
		printf("%c", c);
		fclose(pf);//关闭文件
	}
	return 0;
}

        因为"w" 模式是写入模式,会清空文件内容,在写入之后,读取操作不会得到任何内容。

        换句话说,就是在“w”写入模式下,我们不能用fgetc读取。

        那么有什么办法实现以上代码呢?别急,我们后面会讲。


(3)fgets

        这是一个文本行输入函数,同样适用于所有输入流。

44702c9aaf654848b4ce3a4277c2832c.png

        我们把要存放读取字符串的地址传入,再把读取的字符个数传入,再传入文件指针。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf=fopen("test.txt", "r");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		char c[100] = {0};
		fgets(c,10,pf);
		//puts(c);两种打印方法
		printf("%s", c);
		fclose(pf);//关闭文件
	}
	return 0;
}

        需要注意的是,这个函数同样要再只读模式使用。

输出结果:

4b31c837a9cb4b31a8cc27b4b923e653.png


(4)fputs

        这是一个文本行输出函数,它同样适用于所有输出流。

363296fcbcdf4b26836eab9881becb71.png

        我们要把字符串地址和文件指针传入

使用:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	FILE* pf=fopen("test.txt", "w");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		char c[100] = { 0 };
		strcpy(c, "passion");
		fputs(c, pf);
		fclose(pf);//关闭文件
	}
	return 0;
}

        注意换成了“w”模式。运行结束后,我们发现test.txt中的内容变成了passion。


(5)fscanf

这是一个格式化输入函数,适用于所有输入流。

 d7c24b422656490c99d669d15410c088.png

        我们发现这个函数的原型有些神奇,他的参数里面居然有个省略号!也就是说,它支持传入的参数个数是无限制的!

        这里我们参考scanf来理解(他们只差一个字母f):

#include<stdio.h>
int main()
{
	int a = 0;
	scanf("%d", &a);
	return 0;
}

        这是最最最基础的scanf使用方法。我们可以输入a的数据。

        那如果我们同时输入两个变量的数据呢?

#include<stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a,&b);
	return 0;
}

        它也可以实现。但是在这时候其实scanf里的参数数量已经改变了!我们可以同时输入三个,四个,五个数据都是可以的,

        现在我们来看fscanf,它使用的时候我们要先传入文件指针,其他的参数使用和scanf一样。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	FILE* pf=fopen("test.txt", "r");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		char c[100] = { 0 };
		fscanf(pf,"%s",c);
		printf("%s",c);
		fclose(pf);//关闭文件
	}
	return 0;
}

        我们在test.txt中写上passion,然后运行程序,就发现他能被打印出来啦!


(6)fprintf

        这是一个格式化输出函数,适用于所有输出流。

21ff8c6938d24195af76bef54391b360.png

        它的使用可以类比printf,这里就直接给大家用了不做过多介绍了

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	FILE* pf=fopen("test.txt", "w");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		char c[100] = { 0 };
		strcpy(c, "asdasd");
		fprintf(pf,"%s",c);
		fclose(pf);//关闭文件
	}
	return 0;
}

(7)fread

        这是一个二进制输入函数,适用于文件输入流。

76e1a618b81f488e9b2d4d766cb664b9.png

        这个函数传入的参数就相对来说复杂了一些:

d9da995bc4e6428cb0bff295471b658a.png

        第一个我们传入存放字符串的地址,第二个我们传入每个数据的字节大小,第三个参数我们传入数据的数量;第四个我们传入文件指针。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	FILE* pf=fopen("test.txt", "r");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		char c[100] = { 0 };
		fread(c,1,10,pf);
		printf("%s", c);
		fclose(pf);//关闭文件
	}
	return 0;
}

运行结果:

045d2eed321a4d30baa472e131d4a0bc.png


(8)fwrite

        这是一个二进制输出函数,适用于文件输出流

275f7841249a4486acaa42bd6b0a00a6.png

        我们这里直接给大家上手用了:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	FILE* pf=fopen("test.txt", "w");//打开文件
	int i = 0;
	if (pf != NULL)
	{
		char c[100] = { 0 };
		strcpy(c, "passion");
		fwrite(c,1,10,pf);
		printf("%s", c);
		fclose(pf);//关闭文件
	}
	return 0;
}

运行结果:

4a86f16b8bec4075a40cb1bef09e04b2.png

        好了,今天的内容就分享到这,下一节我们继续学习有关文件操作的知识。觉得有帮助的老铁点点关注支持一下,我们下期再见!



http://www.kler.cn/a/407182.html

相关文章:

  • 并行IO接口8255
  • 使用golang启动一个http代理
  • Docker+Nginx | Docker(Nginx) + Docker(fastapi)反向代理
  • Ease Monitor 会把基础层,中间件层的监控数据和服务的监控数据打通,从总体的视角提供监控分析
  • 【Stable Diffusion】 超大尺寸绘制、分区控制,详解Tiled Diffusion VAE插件功能
  • GitLab|GitLab报错:PG::ConnectionBad: could not connect to server...
  • 如何在Python中进行数学建模?
  • python c++ opencv打开图片路径写法
  • RK356x-10:串口(uart)配置与调试
  • 多算法模型(BI-LSTM GRU Mamba ekan xgboost)实现功率预测
  • ubuntu安装Eclipse
  • 如何在React中服务器操作提交表单后(不)重置表单?
  • Next.js 独立开发教程(三):CSS 样式的完整指南
  • OpenHands:开源AI编程工具的新贵,让编程更自然
  • Rust学习(七):智能指针
  • Vue前端进阶面试题目(二)
  • .NET9 - 新功能体验(二)
  • (udp)网络编程套接字Linux(整理)
  • 4、MAC地址、ARP协议解析
  • 【数据结构】—— 二叉树
  • 跨域相关的一些问题 ✅
  • CodiMD导出pdf失败或无中文
  • MySQL 中的锁
  • PHP实现插入排序
  • 解决 Docker Desktop 启动报错:Docker Desktop is unable to detect a Hypervisor
  • gpt2的学习