C语言文件读写-按字节、按行 + 读写文件时最后一行读取两遍解决方法

文本流

  文本流,也就是我们常说的以文本模式读取文件,文本流的有些特征在不同的系统中可能不同。其中之一就是文本行的最大长度。标准规定至少允许254个字符。另一个可能不同的特性是文本行的结束方式。例如再Windows系统中,文本文件约定以一个回车符和一个换行符结尾。但是再Linux下只使用一个换行符结尾。

   标准C把文本定位为零个或多个字符,后面跟一个表示结束的换行符(\n),对于那些文本行的外在表现形式与这个定义不同的系统上,库函数负责外部形式和内部形式之间的翻译,例如,在Windows系统中,在输出时,文本的换行符被写成一对回车/换行符。在输入时,文本中的回车符被丢弃。这种不必考虑文本的外部形式而操纵文本的能力简化了可移植程序的创建。

二进制流

  二进制流中的字节将完全根据程序编写他们的形式写入到文件中,而且完全根据它们从文件或设备读取的形式读入到程序中,它们并未做任何改变。这种类型的流适用于非文本数据,但是如果你不希望I/O函数修改文本文件的行末字符,也可以把他们用于文本文件。

   C语言在处理这两种文件的时候并不区分,都按成是字符流,按字节进行处理

   我们程序中经常看到的文本方式打开文件和二进制方式打开文件仅仅体现在换行符的处理上。

   比如说,在Windows下,文件的换行符是\r\n,而在Linux下换行符则是\n

   当对文件使用文本方式打开的时候,读写的Windows文件中的换行符\r\n会被替换成\n读到内存中,当在Windows下写入文件的时候,\n被替换成\r\n再写入文件。如果使用二进制方式打开文件,则不进行\r\n和\n之间的转换,那么由于Linux下的换行符就是\n,所以文本文件和二进制文件无区别。

文件读写函数

1.按照字符读写文件 : fgetc(),fputc()

2.按照行读写文件:fputs(),fgets()

3.按照块读写文件:fread(),fwrite()

4.按照格式化读写文件:fprintf(),fscanf()

5.按照随机位置读写文件:fseek(),ftell(),rewind()

按照字符读写文件

#include<stdio.h>
#include<string.h>
#pragma pack(show)



void test01()
{
	int i;
	char ch;
	char buff[] = "hello world";
	FILE* f_read;
	//写文件
	FILE* f_write = fopen("./test1.txt","w");


	if(f_write == NULL)
		return;

	
	for(i = 0;i < strlen(buff);i++)
	{
		fputc(buff[i],f_write);
	}
	fclose(f_write);

	//读文件
	//FILE* f_read = fopen("./test1.txt","r");
	f_read = fopen("./test1.txt","r");
	if(f_read == NULL)
		return;
	while((ch = fgetc(f_read)) != EOF)
	{
		printf("%c",ch);
	}
	fclose(f_read);
}


int main()
{
	test01();

	return 0;
}

运行结果:

hello world

同时在与该.c文件同级目录下会出现一个test1.txt的文件

按行读写文件

#include<stdio.h>
#include<string.h>
#pragma pack(show)



void test01()
{
	int i;
	char ch;
	char temp[1024] = {0};
	
	FILE* f_read;
	//写文件
	FILE* f_write = fopen("./test2.txt","w+");
	char* buff[]=
	{
		"锄禾日当午\n",
		"汗滴禾下土\n",
		"谁知盘中餐\n",
		"粒粒皆辛苦\n"
	};

	if(f_write == NULL)
		return;

	
	for(i = 0;i < 4;i++)
	{
		fputs(buff[i],f_write);
	}
	fclose(f_write);

	//读文件
	//FILE* f_read = fopen("./test1.txt","r");
	f_read = fopen("./test2.txt","r");
	if(f_read == NULL)
		return;

	
	while(!feof(f_read))
	{
	
		fgets(temp,1024,f_read);
		printf("%s",temp);
	}
	fclose(f_read);
}


int main()
{
	test01();

	return 0;
}

运行结果:

锄禾日当午
汗滴禾下土
谁知盘中餐
粒粒皆辛苦
粒粒皆辛苦
请按任意键继续. . .

发现最后一行读取两遍,怎么回事?

stdio.h中可以看到如下定义:

1

2

3

4

5

6

7

8

9

#define EOF (-1)

#define _IOEOF 0x0010

#define feof(_stream) ((_stream)->_flag & _IOEOF)

int c;

while(!feof(fp))

{

    c = fgetc(fp);

    printf("%X\n", c);

}

原因就是在读完最后一个字符后,fp->flag仍然没有被置为_IOEOF,因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到文件结尾。

引用自:https://baike.baidu.com/item/feof/10942186?fr=aladdin

所以改进如下:

fgets(temp,1024,f_read);
    while(!feof(f_read))
    {
        printf("%s",temp);
        fgets(temp,1024,f_read);
        
    }

猜你喜欢

转载自blog.csdn.net/weixin_42596333/article/details/104521765