C语言文件操作详解

本文详细介绍了计算机文件的基本概念,包括文件的构成、Windows中常见文件类型,C程序中的文件处理,二进制和文本文件的区别,文件流的使用(如fopen、fclose、fscanf、fprintf等),文件指针的创建和操作,以及文件读取结束的判定和文件缓冲区的工作原理。
摘要由CSDN通过智能技术生成

1. 什么是文件:

     文件是计算机中存储数据的一种方式,它可以包含文本、图像、音频、视频等各种形式的信息。在计算机系统中,文件被组织成一个个独立的单元,可以通过文件名来标识和访问。文件可以存储在计算机的硬盘、固态硬盘、光盘、U盘等存储介质上,文件通常由两部分组成:文件名和文件内容。文件名是用来标识文件的唯一名称,可以根据需要进行命名。文件内容是实际存储在文件中的数据,可以是文本、二进制数据或其他格式的数据,文件在计算机系统中起到了重要的作用,它们可以用于存储和传输数据,作为程序的输入和输出,以及用于组织和管理数据。通过文件系统,用户可以创建、打开、读取、写入、修改和删除文件。

1.1. windows中文件的类型:

        前边我们聊到不同后缀代表着不同的文件类型,下边我们来了解一下常见的文件类型:

  1. text.txt 后缀为.txt的为文本文件
  2. text.exe 后缀为.exe的为可执行文件
  3. text.jpg 后缀为.jpg的为图片文件
  4. text.mp3 后缀为.mp3的为音频文件
  5. text.mp4 后缀为.mp4的为视频文件

上图中仅为部分文件类型,如有兴趣的小伙伴可以去深入了解喔

1.2. c程序中的文件:

        一个c程序要想变成最终可以执行的文件,会经历编译-->链接-->运行三个步骤,而这三个步骤又分别对应着三个不同的文件.c文件编译以后先生成.o(.obj)文件,链接生成.exe的可执行文件,最终再执行

1.3. 二进制文件及文本文件:

二进制文件:数据在内存当中是以二进制的格式存储的,如果不加以转换直接输出到外存文件当中的称为二进制文件

文本文件:存入文件前加以转换为1ASCII格式存储在文件中的文件为文本文件

举例:假设有一个数字5000,那么它以二进制或文本的形式在内存当中分别是如何存储的呢

(注:相应的ASCII码值对应着不同的十进制数,字符5的ASCII码值为00110101 0为00110000)

2. 文件流:

        文件流是一种用于读取和写入文件的数据流。它提供了一种方便的方式来处理文件的输入和输出操作,我们常使用的printf函数和scanf函数所对应使用的就是标准输入和输出流,只不过这些流在我们打开编译器时已经默认开启了,所以对应程序员来说直接使用即可

c程序默认打开的流:

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

C语言提供了标准库函数来支持文件流操作,主要包括以下几个步骤:

  1. 打开文件:使用fopen函数打开一个文件,并返回一个指向该文件的指针。需要指定文件名和打开模式(如读取、写入、追加等)

  2. 读取文件:使用fscanffgets等函数从文件中读取数据。fscanf可以按照指定的格式从文件中读取数据,而fgets则逐行读取字符串

  3. 写入文件:使用fprintffputs等函数将数据写入文件。fprintf可以按照指定的格式将数据写入文件,而fputs则将字符串写入文件

  4. 关闭文件:使用fclose函数关闭已打开的文件。关闭文件后,将释放相关的资源

C语言文件流的使用需要注意以下几点:

  • 在打开文件时,需要确保文件存在或者具有相应的权限
  • 在读取或写入文件时,需要确保文件指针指向正确的位置
  • 操作完成后,需要及时关闭文件,以释放资源

3. 文件指针的创建:

        文件指针的创建与前文中的指针创建大同小异,FILE* 变量名

int main()
{
	FILE* pf;   //文件的创建
	return 0;
}
定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变 量)通过该⽂件信息区中的信息就能够访问该⽂件,也就是说,通过⽂件指针变量能够间接找到与 它关联的⽂件

举例:

4. 文件的打开与关闭:

4.1. fopen与fclose函数:

fopen函数:打开文件

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

filename:要打开的文件

mode:以什么样的方式打开文件

(如果文件被成功打开,返回一个指向file对象的指针,否则返回NULL)

fclose函数:关闭文件

int fclose ( FILE * stream );

stream:指向file文件的指针,该对象为要关闭的流

(如果文件被成功关闭,返回0,关闭失败,返回EOF)

file打开时mode参数:

举例:

int main()
{
	FILE* pf;   //文件的创建
	pf = fopen("a1.txt", "wb");
	if (pf != NULL)  //判断文件是否打开成功
	{
		int i = 0;
		while (i < 11)
		{
			fputc(i, pf); //fputc写入一个字符
			i++;
		}
		fclose(pf);  //关闭文件
	}
	return 0;
}

5. 文件的顺序读写:

5.1. 顺序读写函数:

5.2. fgets函数:

从文件中获取一个字符

int fgetc ( FILE * stream );

(如果读取成功,返回读取的字符,整形提升至int型,读取失败返回EOF)

举例:

int main()
{
	FILE* p;
	p = fopen("test1.txt", "r");
	if (p != NULL)
	{
		int a = fgetc(p);
		printf("%d", a);
        fclose(p);
	}
	return 0;
}

//执行结果
97 所以该字符是a,a的ASCII值为97

5.3. fputc函数:

写入一个字符到文件中:

int fputc ( int character, FILE * stream );

character:写入的字符

(如果写入成功,则字符被写入到文件当中,失败返回EOF)

举例:

int main()
{
	FILE* p1;
	p1 = fopen("test1.txt", "w");
	if (p1 != NULL)
	{
		fputs("a", p1);
		fclose(p1);
	}
	return 0;
}

//执行结果
此时test1.txt文件当中写入了字符a

5.4. fgets函数:

从文件当中获取字符串

char * fgets ( char * str, int num, FILE * stream );

(如果读取成功,返回str,如果读取到文件末尾,则设置eof指示符(feof),读取失败返回NULL)

举例:

int main()
{
	FILE* p2;
	char a[100];
	p2 = fopen("test1.txt", "r");
	if (p2 != NULL)
	{
		if (fgets(a, 20, p2) != NULL)
		{
			printf("%s", a);
		}
		fclose(p2);
	}
	return 0;
}

5.5. fputs函数:

将字符串写入到文件中

int fputs ( const char * str, FILE * stream );

(如果成功返回一个>0的数,失败函数返回EOF并设置错误指示器)

举例:

int main()
{
	FILE* p3;
	char a[] = "qwerty";
	p3 = fopen("test1.txt", "w");
	if (p3 != NULL)
	{
		int a1 = fputs(a, p3);
		if (a1 >= 0)
			fclose(p3);
		else
			perror("fputs:");
	}
	return 0;
}

5.6. fscanf函数和fprintf函数:

5.6.1. scanf函数以及printf函数:

在讲fscanf以及fprintf这两个函数前,我们先来了解一下scanf和printf函数又是如何使用的呢

语法:

int printf ( const char * format, ... );  //格式化输入函数
int scanf ( const char * format, ... );   //格式化输出函数

下边我们来看看它们是如何使用的:

//从键盘上输入一个数,输出到控制台中
int main()
{
	int a = 0;
	scanf("%d", &a);
	printf("a的值为:%d", a);
	return 0;
}

该两个函数为格式化输入输出函数,所以在使用这两个函数时必须带有格式,那么它们又和fscanf和fprintf有什么区别呢,下边我们一起来了解一下

5.6.2. fscanf,fprintf,scanf及printf四个函数的区别:

语法:
int fscanf ( FILE * stream, const char * format, ... );
int fprintf ( FILE * stream, const char * format, ... );

(如果成功,返回函数成功填充的项数,而匹配失败或者到达文件末尾返回值小于或等于0,在任何数据都未被读取到之前发生错误,fnahuiEOF)

差异对比:

fscanf的使用:
int main()
{
	FILE* p4;
	p4 = fopen("test1.txt", "r+"); //以读的方式打开
	int s = 1000;
	char a2[10] = { 0 };
	if (p4 != NULL)
	{
		int a3 = fscanf(p4, "%d%s", &s,a2); //读取两个数放入相对应的变量当中
		if (a3 != EOF)
		{
			printf("%d\n", s);
			printf("%s\n", a2);
			fclose(p4);
		}
		else
		{
			perror("fscanf");
		}
	}
	return 0;
}
fprintf的使用:
int main()
{
	FILE* p4;
	p4 = fopen("test1.txt", "w+");
	int s = 1000;
	char a2[10] = "abcdef";
	if (p4 != NULL)
	{
		int a3 = fprintf(p4, "%d%s", s, a2);
		if (a3 != EOF)
		{
			fclose(p4);
		}
		else
		{
			perror("fprintf");
		}
	}
	return 0;
}

如何使用fscanf或fprintf将数据输入输出到控制台当中:

(这里就要使用到我们之前所讲的输入输出流了)

举例:

int main()
{
	int a = 0;
	printf("请输入一个数:");
	int q = fscanf(stdin, "%d", &a); //stdin标准输入流
	if (q == EOF)
	{
		perror("fscanf");
	}
	fprintf(stdout, "a此时的值为:%d", a); //stdout标准输出流

	return 0;
}

//执行结果
请输入一个数:123
a此时的值为:123

同理前边适用于所以流的函数都可以如此使用

5.7. fread函数:

以二进制的方式在文件中读取数据

语法:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

(如果读取成功,返回读取的个数,如果size和count为0,则函数返回0,函数内容不发生改变)

ptr:指向大小至少为(size_t count)字节的内存块的指针,转换为void*类型

size:要读取的每个元素大小,单位是字节

count:读取的个数

stream:文件指针

举例:

#include <stdlib.h>
int main()
{
	FILE* p5;
	int count = 5;
	char* pf = (char*)malloc(sizeof(char) * count);
	if (pf == NULL)
	{
		perror("malloc");
		return 1;
	}
	p5 = fopen("test1.txt", "rb"); //以二进制的方式读取数据
	if (p5 != NULL)
	{
		int q = fread(pf, sizeof(char), count, p5);
		for (int i = 0; i < count; i++)
		{
			printf("%c ", *(pf + i));
		}
		fclose(p5);
	}
	else
	{
		perror("fopen");
	}
	free(pf);
	pf = NULL;
}

//执行结果
a b c d e

如有对动态内存malloc这些不理解的小伙伴可以去看看动态内存管理这篇文章哟

5.8. fwrite函数:

语法:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

(与fread函数大同小异,这里博主就不做结束咯)

举例:

#include <stdlib.h>
int main()
{
	FILE* p6;
	int count = 5;
	char a5[] = "sdfgh";
	p6 = fopen("test1.txt", "wb"); //以二进制的方式读取数据
	if (p6 != NULL)
	{
		int q = fwrite(a5, sizeof(char), count, p6);
		fclose(p6);
	}
	else
	{
		perror("fopen");
	}
}

//执行结果
此时成功向test1.txt文件当中添加数组a5中的字符串

6. 文件的随机读取:

6.1 fseek函数:

int fseek ( FILE * stream, long int offset, int origin );

stream:文件指针

offset:二进制文件:要从原点偏移的字节数

             文本文件:要么为0,要么有ftell返回一个值

origin:表示偏移量的开始位置

                SEEK_SET:文件的起始位置

                SEEK_CUR:文件指针当前结束的位置

                SEEK_END:文件的结束位置

(如果成功返回0,否则,返回非零值)

举例:

int main()
{
	FILE* pFile;
	pFile = fopen("test1.txt", "wb");
	fputs("I'm is a handsome guy", pFile); //向文件中写入一组字符
	fseek(pFile, 7, SEEK_SET);  //光标从5的位置开始执行操作
	fputs("no ", pFile);  
	fclose(pFile);
	return 0;
}

//执行结果
I'm is no andsome guy

6.2 ftell函数:

语法:

long int ftell ( FILE * stream );

(如果成功,返回位置指示器当前的值,失败,返回-IL)

举例:

(相较于之前的代码,咱来举例看看)

int main()
{
	FILE* pFile;
	pFile = fopen("test1.txt", "wb");
	fputs("I'm is a handsome guy", pFile); //向文件中写入一组字符
	fseek(pFile, 7, SEEK_SET);  //光标从5的位置开始执行操作
	fputs("no ", pFile);
	long size = ftell(pFile);  //判断文件中光标的位置
	printf("%ld", size);
	fclose(pFile);

	return 0;
}

6.3 rewind函数:

语法:

void rewind ( FILE * stream );

(让文件指针的位置回到起始位置)

举例:

int main()
{
	FILE* p7;
	p7 = fopen("test1.txt", "w");
	if (p7 != NULL)
	{
		int q = fputs("abcdefgh", p7); //向文件当中写入“abcdefg”这个字符串
		if (q == EOF)
		{
			perror("fputs");
		}
		fseek(p7, 4, SEEK_SET);  //此时文件指针应指向e
		rewind(p7);  //将文件指针返回到文件起始位置
		FILE* p8 = fopen("test1.txt", "r");
		char q1 = fgetc(p8);  //此时q1的值应为a
		printf("%c\n", q1);
		fclose(p7);
		fclose(p8);
	}
	else
	{
		perror("fopen");
	}
	return 0;
}

//执行结果
a

7. 文件读取结束的判定:

7.1 错误使用的feof函数:

语法:

int feof ( FILE * stream );

(如果设置l与流相关的文件结束指示符,则返回一个非零值,否则返回零)

牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束
feof 的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束
  1. ⽂本⽂件读取是否结束,判断返回值是否为 EOF fgetc ),或者 NULL fgets
  2. ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数
举例:
int main()
{
	FILE* p9;
	int q = 0;  //记录文件读取的个数
	p9 = fopen("test1.txt", "r");
	if (p9 != NULL)
	{
		while (fgetc(p9) != EOF)
		{
			q++;
		}
		if (ferror(p9))   //文件错误时返回0
			printf("文件读取发生错误!\n");
		else if (feof(p9))
			printf("文件读取完毕\n");
		fclose(p9);
	}
	else
	{
		perror("fopen");
	}
	printf("文件中有多少个字符:%d", q);
	return 0;
}

//执行结果
文件读取完毕
文件中有多少个字符:8   

8. ⽂件缓冲区:

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

下边小博给兄弟们找个一个题解方便大家进一步了解:

(今日分享到此结束,如觉得有帮助还请点赞三联支持一波呢,Thanks♪(・ω・)ノ)

  • 36
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糟糕喔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值