文件操作c语言

外部设备(键盘,文件,网络,光盘)-----》流---.>屏幕,键盘,网络上,u盘,光盘
我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出
操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流
想象成流淌着字符的河。
C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。
⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

标准流

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语⾔程序在启动的时候,默认打开了3个流:
• stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
• stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出
流中。
• stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE* ,通常称为⽂件指针。
C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

文件指针

4.2 ⽂件指针
缓冲⽂件系统中,关键的概念是"⽂件类型指针",简称"⽂件指针"。
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名
字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系
统声明的,取名 FILE.
例如,VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:

cpp 复制代码
char *_ptr;
 int _cnt;
 char *_base;
 int _flag;
 int _file;
 int _charbuf;
 int _bufsiz;
 char *_tmpfname;
 };
typedef struct _iobuf FILE;

每一个文件被打开进行操作,会生成一个文件信息区,其实就是FILE类型的结构体。

有一个文件指针来找到他


不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。
每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信
息,使⽤者不必关⼼细节。
⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。
下⾯我们可以创建⼀个FILE*的指针变量:

文件的打开和关闭

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

cpp 复制代码
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );
1

const char * mode打开的文件的方式:

字符指针指向一个字符

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

关于读和写:(站在程序的角度)

程序里的数据是放在内存里的

文件的顺序读写:

fgetc和fputc针对单个字符的输入和输出

复制代码
int fputc ( int character, FILE * stream );

Write character to stream

写字符到琉里

1.当文件以写的形式打开

就是'w'

cpp 复制代码
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");
		if (pf == NULL)
		{
			perror("fopen");
			return 1;
	
		}
		//写文件
		/*fputc('a', pf);
		fputc('b', pf);
		fputc('c', pf);*/
		char ch = 0;
		for (ch = 'a'; ch <= 'z'; ch++)
		{
			fputc(ch,pf);
		}

		//关闭文件


		fclose(pf);
		pf = NULL;
	return 0;
}

一次写一个字符;光标会不断地向后,所谓顺序

2.当文件以'r'读的形式打开

1.如果成功读取字符的话,返回的是字符的ascll值--char

2.如果读取遇到文件末尾,或者读取失败的话,返回的是EOF就是-1,所以返回的类型设计成int

打印单个字符

cpp 复制代码
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
		if (pf == NULL)
		{
			perror("fopen");
			return 1;
	
		}
		//读文件
		/*fputc('a', pf);
		fputc('b', pf);
		fputc('c', pf);*/
		int ch=fgetc(pf);
		printf("%c\n", ch);

		ch = fgetc(pf);
		printf("%c\n", ch);

		ch = fgetc(pf);
		printf("%c\n", ch);

		//关闭文件


		fclose(pf);
		pf = NULL;
	return 0;
}

打印的a,b,c,光标会后移

打印多个字符

cpp 复制代码
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
		if (pf == NULL)
		{
			perror("fopen");
			return 1;
	
		}
		//读文件
		/*fputc('a', pf);
		fputc('b', pf);
		fputc('c', pf);*/
		int ch = 0;
		while ((ch = fgetc(pf)) != EOF)
		{
			printf("%c", ch);
		}

		//关闭文件


		fclose(pf);
		pf = NULL;
	return 0;
}

fgets和fputs针对文本行的输入和输出

fputs

cpp 复制代码
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs("helloworld", pf);
	fputs("helloworld", pf);
	fclose(pf);
	pf = NULL;

	return 0;
}

写到一行上

从流里面读最多num个字节的数据,放到str指向的空间里面去,就num-1个,为\0留一个位置

读取成功返回str的首地址,读取到文件末尾或失败返回NULL

cpp 复制代码
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	char arr[10] = { 0 };
	fgets(arr, 10, pf);


	fclose(pf);
	pf = NULL;

	return 0;
}

\0是主动放上去的

如果一行不够10个字节

放\n再放\0

cpp 复制代码
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	char arr[10] = { 0 };
	fgets(arr, 10, pf);
	printf("%s", arr);

	fgets(arr, 10, pf);
	printf("%s", arr);
	fclose(pf);
	pf = NULL;

	return 0;
}

要读取完

对于这个

cpp 复制代码
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	char arr[10] = { 0 };
	
	while ((fgets(arr, 20, pf)) != NULL)
	{
		printf("%s", arr);
	}
	fclose(pf);
	pf = NULL;

	return 0;
}

第一行超过20个仍能读出就是因为读完前面19个,自己补上\0,后面有打印直到遇到第一行的\n

scanf和fprintf格式化的输入和输出

fread和fwrite针对二进制的输入和输出

相关推荐
塔能物联运维1 小时前
设备断网时数据丢失,后来启用本地缓存+异步重传队列
java·开发语言·缓存
天涯路s1 小时前
qt怎么自定义日志
开发语言·qt
Evand J1 小时前
【自适应IMM】MATLAB编写的创新多模型,基于CA/CT双模型和观测自适应。二维平面目标位置估计,带误差统计特性输出,附代码下载链接
开发语言·matlab·ekf·imm·交互式多模型
我命由我123452 小时前
微信小程序 - scroll-view 的一些要点(scroll-view 需要设置滚动方向、scroll-view 需要设置高度)
开发语言·前端·javascript·微信小程序·小程序·前端框架·js
7哥♡ۣۖᝰꫛꫀꪝۣℋ2 小时前
Spring IoC&DI
java·开发语言·mysql
wadesir2 小时前
Go语言反射之结构体的深比较(详解reflect.DeepEqual在结构体比较中的应用)
开发语言·后端·golang
你不是我我2 小时前
【Java 开发日记】我们来说一说 Redis IO 多路复用模型
java·开发语言·redis
想七想八不如114082 小时前
408操作系统 PV专题
开发语言·算法