首页 > 其他分享 >c语言--文件操作

c语言--文件操作

时间:2024-09-26 18:22:58浏览次数:3  
标签:文件 语言 -- int pf FILE fopen 函数

一 为什么使用文件?

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

二 什么是文件

磁盘(硬盘)上的⽂件是⽂件。

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

2.1 程序文件  

程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows环境后缀为.exe)。

2.2 数据文件

⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件。 在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到显⽰器上。 其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处理的就是磁盘上⽂件。

2.3 文件名

⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。 ⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀 例如: c:\code\test.txt 为了⽅便起⻅,⽂件标识常被称为⽂件名。

三 二进制文件和文本文件

根据数据的组织形式,数据⽂件被称为⽂本⽂件或者⼆进制⽂件。 数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的⽂件中,就是⼆进制⽂件。 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。
⼀个数据在⽂件中是怎么存储的呢? 字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制形式输出,则在磁盘上只占4个字节。

四 文件的打开和关闭

4.1 流和标准流

4.1.1 流

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

4.1.2 标准流

C语⾔程序在启动的时候,默认打开了3个流:

  • stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
  • stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中。
  • stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。

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

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

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

4.2 文件指针

缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。

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

例如:VS2013 编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:
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结构的变量,这样使⽤起来更加⽅便。
下⾯我们可以创建⼀个FILE* 的指针变量:
FILE* pf; // ⽂件指针变量
定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与它关联的⽂件。

4.3 文件的打开和关闭

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

下面是文件的打开模式:

文件打开方式
文件打开方式含义如果指定文件不存在
“r”(只读) 为了输⼊数据,打开⼀个已经存在的⽂本⽂件 出错
“w”(只写) 为了输出数据,打开一个文本文件建立一个新的文件
"a"(追加)向文本文件尾添加数据建立一个新的文件
"rb"(只读)为了输入数据,打开一个二进制文件出错
“wb"(只写)为了输出数据,打开一个二进制文件建立一个新的文件
"ab"(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建一个新的文件建立一个新的文件
"a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开一个二进制文件出错
"wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

注意:当使用“w”,“wb”,“w+”,“wb+”打开文件时会清除文件原本存储的数据。

代码示例:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
 FILE * pFile;
 //打开⽂件
 pFile = fopen ("myfile.txt","w");
 //⽂件操作
 if (pFile!=NULL)
 {
 fputs ("fopen example",pFile);
 //关闭⽂件
 fclose (pFile);
 }
 return 0;
}

五 文件的读写

读写文件时我们有两种读取方式:顺序读取随机读取

5.1 顺序读写功能介绍

对于顺序读写我们会常用到以下函数:

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

文本输入流

fwrite ⼆进制输出 文本输出流

 fputc函数(包含在头文件stdio.h中)

该函数的作用是用来向文件输入单个字符数据的,看一下该函数的定义:

character:接收所要存入的字符的ASCII值

stream:接收指向所要存入文件的指针

当该函数成功运行时返回所存入字符的ASCII码值,否则返回EOF值。

例题:在文件中写入26个字母

#include<stdio.h>

int main() {
	//fputc函数
	FILE *pf = fopen("date.txt", "w");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	//打开成功  写文件
	int i = 'a';
	for (i = 0; i < 26; i++) {
		fputc('a' + i, pf);
	}
	//关闭文件
	if (fclose(pf) == EOF) {
		//关闭失败
		perror("fclose");
		return 1;
	}
	//关闭成功 设置为空
	pf == NULL;
	return 0;
}

运行结果:

fgetc函数(包含在头文件stdio.h中)

该函数一般被用来读取文件中单个字符数据,来看一下定义:

stream:接收指向所要读取文件的指针

该函数成功读入数据时会返回读取字符的ASCII值,反之则会返回EOF值。

例题:读取date.txt文件中的内容

#include<stdio.h>

int main() {
	//fgetc函数
	FILE *pf = fopen("date.txt", "r");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	//读文件
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF) {
		printf("%c", ch);
	}
	//关闭文件
	fclose(pf);
	pf == NULL;
	return 0;
}

运行结果:

ps:在程序运行时每次使用fgetc函数读入数据时文件指针在向后移动使其读取的数据不会重复。

  fputs函数(包含在头文件stdio.h中)

读写文件时,我们可以使用fputs函数直接向文件写入一个字符串

str:接收指向将要存入字符串的指针

stream:接收指向所要存入文件的指针

该函数成功运行返回一个非负值,否则返回EOF值。

示例:写入两行字符串

#include<stdio.h>

int main() {
	//fputs函数
	FILE *pf = fopen("date.txt", "w");
		if (pf == NULL) {
			perror("fopen");
			return 1;
		}
		//写文件  字符串不会自动换行 如果想写多行 要在字符串末尾添加换行符
		fputs("hellow,world!\n", pf);
		fputs("my name is Lim!\n", pf);
		fclose(pf);
		pf == NULL;
		return 0;
}

运行结果:

fgets函数(包含在头文件stdio.h中)

 对于输出文件文本行(字符串)数据一般使用fgets函数来进行操作,看一下该函数的定义:

str:接收指向储存读出数据的字符串指针

num:接收要复制到 str 中的最大字符数(包括终止空字符

stream:接收指向所要读取文件的指针

成功后,该函数返回 str的头指针
如果在尝试读取字符时遇到文件结尾,则会设置 eof 指示符 。如果在读取任何字符之前发生这种情况,则返回的指针为空指针(并且 str 的内容保持不变)。
如果发生读取错误,则设置错误指示器 (ferror) 并返回空指针(但 str 所指向的内容可能已更改)。

示例:读取文件中的字符

#include<stdio.h>

int main() {
	//fgets函数
	FILE *pf = fopen("date.txt", "r");
		if (pf == NULL) {
			perror("fopen");
			return 1;
		}
		//读文件  
		char arr[10];
		fgets(arr,5,pf);
		printf("%s",arr);
		fclose(pf);
		pf == NULL;
		return 0;
}

运行结果:

我们可以看到程序只读取了前四个字符,因为fgets函数会把最后一个位置留给'\0'.

如果你想把文件里的内容都读出来,可以尝试以下代码

#include<stdio.h>

int main() {
	//fgets函数
	FILE *pf = fopen("date.txt", "r");
		if (pf == NULL) {
			perror("fopen");
			return 1;
		}
		//读文件  
		char arr[100];
		while (fgets(arr, 100, pf) != NULL) {
			printf("%s", arr);
		}	
		fclose(pf);
		pf == NULL;
		return 0;
}

运行结果:

fprintf函数(包含在头文件stdio.h中)

fprintf函数可以向文件输出任意数据,让我们来看一下该函数的定义:

stream:接收指向所要输出文件的指针

format:接收将要输出数据的格式(和printf函数一样有%d,%x,%c,%s等等格式类型)

将该函数与printf函数对比

我们发现,printf函数只是少了一个参数就是FILE*类型的stream。

示例:

#include<stdio.h>
int main() {
	int num = 100;
	float score = 75.5;
	char name[100] = "张三";
	//打开文件
	FILE *pf = fopen("date.txt", "w");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	}
	//写文件
	fprintf(pf,"%d %.1f %s\n",num,score,name);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

运行结果:

  fscanf函数(包含在头文件stdio.h中)

fscanf函数是可以读取各种类型的数据的函数,让我们看一下定义:

stream:接收指向所要输入文件的指针

format:接收将要输入数据的格式(和scanf函数一样有%d,%x,%c,%s等等格式类型)

将该函数与scanf函数对比

我们发现唯一多出来的一个参数也是FILE*类型的stream

示例:

#include<stdio.h>
int main() {
	//fscanf函数
	int num = 0;
	float score = 0;
	char name[100] = {0};
	//打开文件
	FILE *pf = fopen("date.txt", "r");
	if (pf == NULL) {
		perror("fopen");
		return 1;
	} 
	//读文件
	fscanf(pf, "%d %f %s\n", &num, &score, name);
	printf("%d %f %s\n", num, score, name);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

运行截图:

fwrite函数(包含在头文件stdio.h中)

fwrite函数可以直接将计算机内存中所存储的二进制数据输出到文件中,让我们来看一下定义:

ptr:接收指向所要输入数据的指针或地址

size:接收输出的每个数据的大小(以字节为单位)

count:所要输出数据的个数

stream:接收指向所要输出文件的指针

示例:

#include<stdio.h>
int main() {
	//fwrite函数
	FILE *pf = fopen("date.txt", "wb");//二进制的写
		if (pf == NULL) {
			perror("fopen");
			return 1;
		} 
		//二进制的形式写
		int arr[] = { 1,2,3,4,5 };
		fwrite(arr, sizeof(arr[0]), 5, pf);
		fclose(pf);
		pf = NULL;
	return 0;
}

运行结果:

fread函数(包含在头文件stdio.h中)

fread函数使用二进制的方式读取,让我们看一下定义:

ptr:传入指向将要存储数据的变量的指针或地址

size:传入每次从文件读取数据的大小(以字节为单位)

count:传入将要读取的次数

stream:接收指向所要输入文件的指针

示例:

#include<stdio.h>
int main() {
	FILE *pf = fopen("date.txt", "wb");//二进制的读
		if (pf == NULL) {
			perror("fopen");
			return 1;
		} 
		//二进制的形式读
		int arr[5] = { 0 };
		int i = 0;
		for (i = 0; i < 5; i++) {
			fread(&arr[i], sizeof(arr[0]), 1, pf);
		}
		for (i = 0; i < 5; i++) {
			printf("%d ", arr[i]);
		}
		fclose(pf);
		pf = NULL;
	return 0;
}

运行结果:

六 ⽂件读取结束的判定

6.1被错误使⽤的 feof

6.1.1 判断文本文件的结束

牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。 feof 的作⽤是:当⽂件读取结束的时候,判断读取结束的原因是否是:遇到⽂件尾结束
判断⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets ) 例如:
  • fgetc 判断是否为 EOF .
  • fgets 判断返回值是否为 NULL .

6.1.1 判断二进制文件的结束

⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数
例如: fread判断返回值是否⼩于实际要读的个数。

七 文件缓冲区

 ANSIC标准采用"缓冲文件系统"处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块"文件缓冲区"。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

以下是程序向硬盘输入数据和硬盘向程序输出数据的流程:

代码示例:

#include<stdio.h>
#include<Windows.h>
int main()
{
	//打开
	FILE* pf = fopen("date.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//存入
	fputs("asdfghj", pf);//将代码放在输出缓冲区
	printf("睡眠20秒-已经写数据了,打开文件是没有数据的\n");
	Sleep(20000);//睡眠20秒
	printf("刷新缓冲区\n");
	fflush(pf);//此函数可以刷新缓冲区中的数据,使其存入硬盘文件中
	//fflush在高版本的VS上已经不能使用了
	printf("此20秒数据从文件缓冲区内读入到文件中,打开文件是有数据的\n");
	Sleep(20000);
	//关闭
	fclose(pf);
	//注 flcose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

运行结果:

这里可以得出一个结论: 
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
如果不做,可能导致读写文件的问题。


祝大家生活愉快。

标签:文件,语言,--,int,pf,FILE,fopen,函数
From: https://blog.csdn.net/2303_80645930/article/details/142436515

相关文章

  • 在Bamboo上怎么使用iOS的单元测试
    本教程将使用北汽登录模块为例,一步一步和大家一起搭建单元测试用例,并在Bamboo上跑起来,最终测试结果和代码覆盖率会Bamboo上汇总。模块名称:BQLoginModule,是通过iBiu创建的一个模块工程一建立单元测试BundleProductName:BQLoginTests二测试代码编写1配置文件同步如果我们要在测......
  • 什么是ETL?什么是ELT?怎么区分它们使用场景
    ELT和ETL这两种模式从字面上来看就是一个顺序颠倒的问题,每个单词拆开来看其实都是一样的。E代表的是Extract(抽取),也就是从源端拉取数据;T代表的是Transform(转换),对一些结构化或者半结构化的数据进行一些处理,比如数据加密、字段转换、映射、拼接等操作;L代表的是Load(加载),也就是将数据写......
  • 视频压缩工具哪个好?没有充足内存的朋友用这几个工具就对了
    是不是每次录完视频,看着那惊人的文件大小就头疼不已?想发朋友圈又怕占内存的朋友快看过来吧~我有办法能让视频既拥有小巧体积又维持清晰画质——借助高质量的视频压缩手机app和软件就可以啦!今天我就来好好向大家安利几款配备智能压缩算法的优质工具,相信它们超强的实力能够帮你......
  • 嘉林文化传媒(绍兴)有限公司是一家出品公司曾出品过《盛夏里的旧时光》...嘉林娱乐引领
    嘉林文化传媒(绍兴)有限公司出品的影视剧《盛夏里的旧时光》是一部备受期待的作品。这部剧以其深刻的情感和引人入胜的剧情,讲述了年幼时不幸失去双亲的林屿嘉展开,他在冰冷的亲戚家中度过了十个春秋。十六岁那年,林屿嘉的生活因转学到许肆家附近而发生转折,两个少年由此建立起深厚的友谊......
  • 微型丝杆的行业应用!
    微型丝杆作为一种高精度、小尺寸的机械传动元件,在现代工业中扮演着重要角色,在多个行业中都有广泛的应用,主要包括以下几个方面:1、医疗设备:在手术机器人中,微型丝杆能够实现精准定位和操作,显著提高手术的准确性和安全性,在康复设备中,微型丝杆则帮助患者进行精确的康复训练,促进康复进程......
  • 有哪些同声传译软件?它们帮你实时应对不同语言的挑战
    相信同声传译这项工作,对于许多人来说是个不小的挑战~不过在跨国的商务会议或者学术交流中,如何准确高效地传达信息是大家首先要考虑的问题,因此同声传译软件就成了我们的必备工具之一。如果大家也正在寻找一款适合用于同声传译日语的软件,那么我接下来要介绍的这五款软件可能会......
  • 酒店预订小程序:如何快速提高酒店的销量?
    酒店行业作为一个传统的发展行业,一直处于需求率旺盛阶段,大众不管外出旅行、出差等都需要预订酒店,持续推动行业的发展。不过,随着消费模式的转变,消费者对酒店的需求也开始逐渐趋向个性化、多元化,这也为酒店的发展转型提供了新的方向。酒店预订小程序是一个基于微信平台的系统,既可以帮......
  • 【ppt技巧】一张幻灯片内多张图片顺序播放
    ​想要在PPT文件的一张幻灯片中插入多张图片,想要将图片,如何设置图片一张张的按顺序播放呢?我们一起来学习一下:首先,我们先将需要的图片都添加到幻灯片中然后我们点击工具栏中的动画功能,对每张图片都设置好动画效果,设置好动画效果之后每张图片左上角都出现了数字,这和你设置动画......
  • repo 简单搭建学习记录
    repo简单搭建学习记录一、repo搭建参考:repo仓库搭建教程【CSDN】gitrepo工具详细使用教程【CSDN】搭建Repo服务器【CSDN】使用REPO管理GIT多仓库1、服务端repo需要一个服务端(manifest仓库),用来列出所有子仓库的路径等信息,如果在github等远程托管平台创建服务端,那......
  • 思迈特软件与柏睿数据再次完成产品兼容性互认证
    近期,经思迈特软件和柏睿数据联合测试,思迈特商业智能与数据分析软件[简称:SmartbiInsight]V11与北京柏睿数据技术股份有限公司(简称“柏睿数据”)的RapidsDBV4.3兼容性良好、运行稳定、性能卓越,完成产品兼容性互认。这是继2018年双方产品首次双向连通认证后,又一次完成产品兼容测试,Rap......