关于文件的理解

本文详细介绍了文件名的构成、文件操作的基本流程,包括文件的打开、关闭、不同方式的读写(如fgetc/fputc、fgets/fputs、fscanf/fprintf等)以及文件定位函数如fseek/ftell、重置文件位置的rewind和feof的使用。
摘要由CSDN通过智能技术生成

在学习文件之前,我们得先了解什么叫做文件名。

所谓的文件名包括三个部分:文件路径+文件名主干+文件后缀

例如:c:\code\test.txt这个就是一个文件名

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

文件的打开和关闭

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

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

下面是能在文件中使用的方式:

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

不知道大家发现了什么规律没有:凡是带 r 的都是关于二进制的,凡是带 a 的如果指定文件不存在则出错,其他的都是建立一个新的文件

下面简单写个代码介绍:

#include <stdio.h>
int main ()
{
    FILE * pFile;
    //打开文件
    pFile = fopen ("myfile.txt","w");//如果没有这个文件则新建一个
    //文件操作
    if (pFile!=NULL)//如果这个文件不为空进入,并写入下面这段代码,然后关闭
    {
    fputs ("fopen example",pFile);
    //关闭文件
    fclose (pFile);
    }
    return 0;
}

文件的顺序读写

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

对比一组函数:

fgetc和fputc

fgetc():
  • 功能:从指定的文件流(FILE类型指针)中读取一个字符。
  • 返回值:成功时返回读取到的字符,并将其转换为整型(int类型),通常可以赋值给char变量。如果到达文件末尾或者发生错误,则返回EOF(通常定义为-1)。
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("pf");
		return 1;
	}
	int ch;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c", ch);
	}
	fclose(pf);
	pf = NULL;
}

首先我们得保证test.txt文件存在才能使用 r ,如果没有可以现在当前路径下创建一个,然后在指定的test.txt文件里面存放需要的字符,然后才能将数据打印在屏幕上,不然屏幕上啥也没有。

fputc():
  • 功能:向指定的文件流(FILE类型指针)中写入一个字符。
  • 返回值:成功时返回写入的字符(作为整型),如果发生错误则返回EOF。
int main()
{
	FILE* pf = fopen("test2.txt","w");
	if (pf == NULL)
	{

		perror("pf");
		return 1;
	}
	int ch = 'A';
	int ret = fputc(ch, pf);//将字符'A'写入到文件里面
	fclose(pf);
	pf = NULL;
	return 0;
}

这里使用的是“w”可以不新建文件,然后我们将字符“A”输入到文件“test2.txt”里面去,运行一下,然后打开指定文件就可以看到里面多了一个字符“A”了。

总结来说,fgetc() 用于从文件读取单个字符,而 fputc() 用于向文件写入单个字符。

fgets和fputs

fgets():

功能:从指定的文件流(FILE类型指针)读取一个字符串,并将其存储到缓冲区中。读取时会考虑换行符('\n'),如果读取到了换行符或到达了指定的最大字符数(包括结束的空字符 '\0'),则停止读取。

函数原型:

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

其中:

  • str 是指向接收读取内容的字符数组的指针。
  • n 指定要读取的最大字符数,不包括终止的空字符 '\0'。
  • stream 是指向打开的文件流的指针。
  • int main()
    {
    	FILE* pf = fopen("test3.txt", "r");
    	if (pf == NULL)
    	{
    		perror("pf");
    		return 1;
    	}
    	char arr[20];
    	if(fgets(arr, sizeof(arr), pf));
    	{
    		printf("%s", arr);// 输出读取到的字符串
    	}
    	fclose(pf);
    	pf = NULL;
    	return 0;
    }

    对于这段代码我是这样理解的:首先得有一个test3.txt文件,然后用将pf里面的内容输出最大sizeof(arr)个字符到arr里面去,最后打印arr,也就是test3.txt里面的内容

fputs():

功能:将一个字符串写入到指定的文件流(FILE类型指针)。它不会自动添加换行符,若需要在字符串后添加换行符,应手动包含在字符串内。

函数原型:

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

其中:

  • str 是指向要写入的字符串的指针。
  • stream 是指向打开的文件流的指针。
int main()
{
	FILE* pf = fopen("test4.txt","w");
	if (pf == NULL)
	{
		perror("pf");
		return 1;
	}
	char* ch = "hello world";
	fputs(ch, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

这段代码是将ch的内容通过fputs存放到pf里面,打开test4.txt即可看见这段“hello world”

fscanf和fprintf

fscanf():

功能:从指定的文件流(FILE类型指针)读取格式化的数据。

函数原型:

int fscanf(FILE *stream, const char *format, ...);

其中:

  • stream 指向要读取的已打开文件流。
  • format 是一个格式字符串,它告诉函数如何解析和解释从文件读取的数据。
  • 可变参数列表根据 format 中指定的格式接收并存储读取到的数据。
int main()
{
	char c[20];
	int a;
	double d;
	FILE* pf = fopen("test5.txt", "r");
	if (pf == NULL)
	{
		perror("pf");
		return 1;
	}
	fscanf(pf, "%s %d %lf", c, &a, &d);
	printf("%s %d %lf", c, a, d);
	fclose(pf);
	pf = NULL;
	return 0;
}

可以这样理解:第一个参数为存放数据的文件,第二个参数为打印参数的格式,第三个参数为参数的地址(因为数组名就是首元素的地址,所以c不需要使用&取地址操作符)

fprintf():

功能:将格式化的数据写入到指定的文件流(FILE类型指针)。

函数原型:

int fprintf(FILE *stream, const char *format, ...);

其中:

  • stream 指向要写入的已打开文件流。
  • format 是一个格式字符串,它告诉函数如何格式化输出的数据。
  • 可变参数列表提供了需要按照 format 格式化并写入文件的数据。
int main()
{
	FILE* pf = fopen("test6.txt", "w");
	if (pf == NULL)
	{
		perror("pf");
		return 1;
	}
	int a = 10;
	char* str = "abcdef";
	double d = 3.14;
	fprintf(pf, "%d %s %lf", a, str, d);
	fclose(pf);
	pf = NULL;
	return 0;
}

第一个参数可以理解为要将数据存放到哪个文件里面去,第二个参数可以理解打印参数的格式,第三个则就是数据

fread和fwrite

fread():

功能:从指定的文件流(FILE类型指针)读取指定长度的数据块到内存缓冲区。

函数原型:

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

其中:

  • ptr 指向用于接收数据的缓冲区地址。
  • size 表示每个元素的大小(以字节为单位)。
  • count 表示要读取的元素数量。
  • stream 是指向已打开文件的FILE指针。
int main()
{
	FILE* pf = fopen("test7.bin", "rb");
	if (pf == NULL)
	{
		perror("pf");
		return 1;
	}
	int buffer[10];
	size_t k = fread(buffer, sizeof(int), 10, pf);
	if (k != 10)
	{
		fprintf(stderr, "Error reading from file.\n");
	}
	fclose(pf);
	pf = NULL;
	return 0;
}
fwrite():

功能:将内存缓冲区中的指定长度的数据块写入到指定的文件流(FILE类型指针)。

函数原型:

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

其中参数含义与 fread() 相似,只是方向相反:

  • ptr 指向包含要写入数据的缓冲区地址。
  • size 表示每个元素的大小(以字节为单位)。
  • count 表示要写入的元素数量。
  • stream 是指向已打开文件的FILE指针。
int main()
{
	FILE* fp = fopen("test8.bin", "wb");
	if (fp == NULL) {
		perror("Error opening file");
		return 1;
	}

	int buffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	size_t items_written = fwrite(buffer, sizeof(int), 10, fp);

	if (items_written != 10)
	{
		fprintf(stderr, "Error writing to file.\n");
	}
    fclose(fp)
	return 0;
}

总结起来,fread() 用于从二进制文件中读取数据块,而 fwrite() 则用于向二进制文件中写入数据块。这两个函数都适合处理结构化数据或不关心字符编码的原始数据,它们根据指定的元素大小和数量高效地移动数据。

sscanf和sprintf

sscanf 和 sprintf 是C语言中用于处理字符串输入输出的标准库函数,它们与文件输入输出的 fscanf 和 fprintf 类似,但操作的对象是内存中的字符串而不是文件。

sscanf():

功能:从给定的字符串中读取格式化的数据。

函数原型:

int sscanf(const char *str, const char *format, ...);

其中:

  • str 指向包含要解析数据的字符串。
  • format 是一个格式字符串,它告诉函数如何解析和解释字符串中的数据。
  • 可变参数列表根据 format 中指定的格式接收并存储读取到的数据。
int main()
{
	char input[] = "123 abc XYZ";
	int number;
	char str[50];

	if (sscanf(input, "%d %s", &number, str) == 2) {
		printf("Number: %d\nString: %s\n", number, str);
	}
	else {
		printf("Error parsing string.\n");
	}
	return 0;
}
sprintf():

功能:将格式化的数据写入到一个字符数组中,生成格式化的字符串。

函数原型:

int sprintf(char *str, const char *format, ...);

其中:

  • str 指向用于存放格式化后字符串的缓冲区地址。
  • format 是一个格式字符串,它指导函数如何格式化输出的数据。
  • 可变参数列表提供了需要按照 format 格式化并放入字符串的数据。
int main() 
{
  int a = 10;
  double b = 3.14;
  char c[20] = "Hello, World!";

  char buffer[100];
  sprintf(buffer, "%d %f %s", a, b, c);

  printf("Formatted string: %s\n", buffer); // 输出:10 3.140000 Hello, World!

  return 0;
}

总结起来,sscanf() 用于从字符串中提取格式化数据,而 sprintf() 则用于创建一个格式化的字符串。这两个函数都需要一个格式字符串来指导如何解析或格式化数据,并且在处理字符串时要注意防止缓冲区溢出,确保目标字符串足够大以容纳所有格式化后的数据。

文件的随机读写

fseek

作用:根据文件指针的位置和偏移量来定位文件指针

int fseek ( FILE * stream, long int offset, int origin );
  • stream:指向已打开文件的FILE结构体指针,即你想移动文件读写位置的那个文件。
  • offset:从whence参数所指定的位置开始偏移的字节数。正数表示向前移动(文件末尾方向),负数表示向后移动(文件开头方向)。
  • whence:指定起始点,有以下三种可能的值:
    • SEEK_SET(或0):从文件开始处偏移offset个字节。
    • SEEK_CUR(或1):从当前文件位置处偏移offset个字节。
    • SEEK_END(或2):从文件结尾处偏移offset个字节。

返回值:

  • 如果成功,fseek() 返回0,表示文件位置指示器成功地移动到了新的位置。
  • 如果失败,例如如果文件不是随机访问类型或者发生其他错误,fseek() 将返回一个非零值,并且errno会被设置为相应的错误代码。

如果不明白请看下面这段代码:

int main()
{
	FILE* pFile;
	pFile = fopen("example.txt", "wb");
	fputs("This is an apple.", pFile);
	fseek(pFile, 9, SEEK_SET);
	fputs(" sam", pFile);
	fclose(pFile);
	return 0;
}

最开始的指针是指向T这个位置的,然后向后偏移了9字节,指向了an的n位置,然后将n ap(共4个字节)替换成了 sam(注意:空格也得算进入)

这是最开始的:                                   这是替换后的:

ftell

作用:返回文件指针相对于起始位置的偏移量

函数原型:

long int ftell(FILE *stream);
  • stream:指向已打开文件的FILE结构体指针,你想获取其当前位置的那个文件。

返回值:

  • 如果成功,ftell() 返回当前文件位置指示器相对于文件开始处的字节数。
  • 如果失败,例如如果文件不是随机访问类型或者发生其他错误,ftell() 将返回 -1L,并且errno会被设置为相应的错误代码。
int main()
{
	FILE* pf = fopen("myfile.txt", "rb");
	if (pf == NULL)
	{
		perror("Error opening file");
	}
	fseek(pf, 0, SEEK_END);
	long size = ftell(pf);
	printf("%ld", size);
	return 0;
}

ftell可以用来当不知道指针指向哪里的时候,用它来计算相对于起始位置的字节数,这样就可以清楚位置了。

rewind

作用:让文件指针的位置回到文件的起始位置

函数原型:

void rewind(FILE *stream);
  • stream:指向已打开文件的FILE结构体指针,你想将其内部指针重置到文件起始位置的那个文件。

该函数没有返回值,直接将文件读写位置移动到文件开头。这相当于调用 fseek(stream, 0, SEEK_SET)

int main()
{
	FILE* pf = fopen("data.txt", "w+");
	int i;
	char buffer[27];
	for (i = 'A'; i <= 'Z'; i++)
	{
		fputc(i, pf);
	}
	rewind(pf);
	fread(buffer, 1, 26, pf);
	fclose(pf);
	buffer[26] = '\0';
	puts(buffer);
	return 0;
}

 feof

在文件读取过程中,不能用feof函数的返回值直接来判断文件是否结束。

feof 的作用是:当文件读取结束的时候,判断读取结束的原因是否是:遇到文件尾结束。

1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL .
2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值