C language--file operation (2)

Preface

        In the previous article, we learned about the related functions of file operations. Today we will explore the knowledge of binary files and file buffers.


1. Text files and binary files

Depending on how the data is organized, data files are calledtext filesorbinary files a>.

  • The data is stored in binary form in the memory. If it is output to external memory without conversion, it is a binary file.
  • If it is required to be stored in ASCII code in external storage, it needs to be converted before storage. Files stored in the form of ASCII characters are text files.

How is data stored in memory?

  • Characters are always stored in ASCII form, and numerical data can be stored in either ASCII or binary form.
  • For example, if there is an integer 10000, if it is output to the disk in the form of ASCII code, it will occupy 5 bytes on the disk (one byte for each character), while if it is output in binary form, it will only occupy 4 bytes on the disk (VS2013 test ).

#include <stdio.h>
int main()
{
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
	fclose(pf);
	pf = NULL;
	return 0;
}

        After we run this code, when we open the "test.txt" document in text mode, garbled characters are displayed. If we open it in binary mode, it can be displayed normally.


2. Determination of completion of file reading

2.1 Misused feof

Remember: During the file reading process, the return value of the feof function cannot be used to directly determine whether the file is ended.
Instead, it is used when the file reading ends to determine whether the reading fails or the end of the file is encountered.
1. Check whether the text file reading is completed and determine whether the return value is EOF (fgetc) or NULL (fgets).
For example:

  • fgetc determines whether it is EOF.
  • fgets determines whether the return value is NULL.

2. Judgment of the end of reading of the binary file, judging whether the return value is less than the actual number to be read.
For example:

  • fread determines whether the return value is less than the actual number to be read.

Correct usage:
Text file example
:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	int c; // 注意:int,非char,要求处理EOF
	FILE* fp = fopen("test.txt", "r");
	if (!fp) {
		perror("File opening failed");
		return EXIT_FAILURE;
	}
	//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
	while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
	{
		putchar(c);
	}
	
	//判断是什么原因结束的
	if (ferror(fp))
		puts("I/O error when reading");
	else if (feof(fp))
		puts("End of file reached successfully");
	fclose(fp);
}

Note:1.ferror--After the file is read, it is used to determine whether an error occurred during the reading process of the file< /span> and ends.

            2.feof--After the file is read, it is used to determine whether the file is in the process of readingThe end of file flag is encountered And end.


Binary file example:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
	double a[SIZE] = { 1.,2.,3.,4.,5. };
	FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式
	fwrite(a, sizeof * a, SIZE, fp); // 写 double 的数组
	fclose(fp);
	double b[SIZE];
	fp = fopen("test.bin", "rb");
	size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 读 double 的数组
	if (ret_code == SIZE) {
		puts("Array read successfully, contents: ");
		for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
		putchar('\n');
	}
	else { // error handling
		if (feof(fp))
			printf("Error reading test.bin: unexpected end of file\n");
		else if (ferror(fp)) {
			perror("Error reading test.bin");
		}
	}
	fclose(fp);
}

        When the code reaches (if (ret_code == SIZE)), it is judged whether so many bytes of data were successfully read during the reading operation. If so, it will be printed out. If not, it will be judged by feof and ferror. , what error occurred that caused the reading to end.


3. File buffer

        Ansic standard uses " Cushion File System The so -called buffer file system refers to Each file being used in the program opens up a "File Buffer". The data output from the memory to the disk will be sent to the buffer in the memory first, and then sent to the disk together after the buffer is filled. If data is read from the disk to the computer, the data is read from the disk file and input into the memory buffer (the buffer is filled), and then the data is sent from the buffer to the program data area (program variables, etc.) one by one. The size of the buffer is determined by the C compilation system.

        Why is the data not placed directly on the hard disk, but through the buffer? When we use functions such as fputc and fwrite, we need to call the system interface. If called frequently, it will reduce the efficiency of the operating system, because the system does not only serve this one program. If the data is output from the memory to the disk, it will be sent to the memory first. The buffer is filled and sent to the disk together. This can greatly improve the efficiency of the operating system.

Prove the existence of the buffer:

#include <stdio.h>
#include <windows.h>
//VS2022 WIN11环境测试
int main()
{
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//先将代码放在输出缓冲区
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

Sleep for 10 seconds - data has been written. Open the test.txt file and find that the file has no content.

Sleep for another 10 seconds - at this time, open the test.txt file again and the file will have content.

A conclusion can be drawn here:         Because of the existence of the buffer, the C language is operating When opening a file, needs to refresh the buffer or close the file at the end of the file operation. Failure to do so may cause problems reading and writing files.

Guess you like

Origin blog.csdn.net/2301_76618602/article/details/133742185