[C Language] Key Contents of File Operations

This article directory

1. What is a document

1.1 Program files

1.2 Data files

1.3 File name

2. Opening and closing of files

2.1 File Pointer

2.2 Opening and closing of files

3. Sequential reading and writing of files

3.1 Introduction to sequential read and write functions

4. Random reading and writing of files

4.1 fseek

4.2 ftell

4.3 rewind

5. Text files and binary files

6. Judgment of the end of file reading

6.1 misused feof 

7. File buffer


1. What is a document

Files on disk are files.

But in program design, we generally talk about two types of files: program files and data files (classified from the perspective of file functions).

1.1 Program files

Including source program file (suffix .c), object file (windows environment suffix .obj), executable program (windows environment suffix .exe).

1.2 Data files

The content of the file is not necessarily the program, but the data read and written when the program is running, such as the file from which the program needs to read data, or the file that outputs the content.

This article discusses data files.

In the previous study, the input and output of the processed data were all targeted at the terminal, that is, the data was input from the keyboard of the terminal, and the running results were displayed on the monitor.

In fact, sometimes we will output the information to the disk, and then read the data from the disk into the memory for use when needed. What is processed here is the file on the disk.

1.3 File name

A file must have a unique file identifier for user identification and reference.

The file name consists of 3 parts: file path + file name trunk + file suffix

For example: c:\code\test.txt 

For convenience, the file ID is often referred to as the file name .

2. Opening and closing of files

2.1 File Pointer

In the cache file system, the key concept is " file type pointer ", referred to as " file pointer ".

Each used file has opened up a corresponding file information area in the memory, which is used to store the relevant information of the file (such as the name of the file, the status of the file and the current location of the file, etc.). This information is stored in a structure variable. The structure type is declared by the system, named FILE .

For example, the stdio.h header file provided by the VS2013 compilation environment has the following file type declaration:

struct _iobuf {
	char* _ptr;
	int _cnt;
	char* _base;
	int _flag;
	int _file;
	int _charbuf;
	int _bufsiz;
	char* _tmpfname;
};
typedef struct _iobuf FILE;

The contents of the FILE type of different C compilers are not exactly the same, but they are similar.

Whenever a file is opened, the system will automatically create a variable of the FILE structure according to the situation of the file, and fill in the information, and the user does not need to care about the details.

Generally, the variables of this FILE structure are maintained through a FILE pointer, which is more convenient to use.

Below we can create a FILE* pointer variable:

FILE* pf;//文件指针变量

Define pf as a pointer variable pointing to FILE type data. You can make pf point to the file information area of ​​a certain file (it is a structure variable). The file can be accessed through the information in the file information area. That is to say, the file associated with it can be found through the file pointer variable .

for example:

2.2 Opening and closing of files

Files should be opened before reading and writing , and should be closed after use .

When writing a program, when opening a file, a FILE* pointer variable will be returned to point to the file, which is equivalent to establishing the relationship between the pointer and the file.

ANSIC stipulates that the fopen function is used to open the file, and the fclose is used to close the file.

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

Open as follows:

file usage meaning If the specified file does not exist
"r" (read-only) To enter data, open an existing text file go wrong
"w" (write only) To output data, open a text file create a new file
“a” (append) Add data to the end of the text file create a new file
"rb" (read-only) To enter data, open a binary file go wrong
"wb" (write only) To output data, open a binary file create a new file
“ab” (append) append data to the end of a binary file create a new file
"r+" (read and write) Open a text file for reading and writing go wrong
"w+" (read and write) Create a new file for reading and writing create a new file
"a+" (read and write) Open a file for reading and writing at the end of the file create a new file
"rb+" (read and write) Open a binary file for reading and writing go wrong
"wb+" (read and write) Create a new binary file for reading and writing create a new file
"ab+" (read and write) Open a binary file for reading and writing at the end of the file create a new file

Example code:

/* 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;
}

3. Sequential reading and writing of files

3.1 Introduction to sequential read and write functions

Function Function name apply to
character input function fgetc all input streams
character output function fputc all output streams
text line input function fgets all input streams
text line output function fputs all output streams
format input function fscanf all input streams
format output function fprintf all output streams
binary input fread document
binary output fwrite document

4. Random reading and writing of files

4.1 fseek

Positions the file pointer based on the file pointer's position and offset.

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

example:

/* fseek example */
#include <stdio.h>

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;
}

4.2 ftell

Returns the offset of the file pointer relative to the starting position.

long int ftell ( FILE * stream );

example:

/* ftell example : getting size of a file */
#include <stdio.h>

int main()
{
	FILE* pFile;
	long size;

	pFile = fopen("myfile.txt", "rb");
	if (pFile == NULL) perror("Error opening file");
	else
	{
		fseek(pFile, 0, SEEK_END); // non-portable
		size = ftell(pFile);
		fclose(pFile);
		printf("Size of myfile.txt: %ld bytes.\n", size);
	}
	return 0;
}

4.3 rewind

Return the position of the file pointer to the beginning of the file.

void rewind ( FILE * stream );

example:

/* rewind example */
#include <stdio.h>

int main()
{
	int n;
	FILE* pFile;
	char buffer[27];

	pFile = fopen("myfile.txt", "w+");
	for (n = 'A'; n <= 'Z'; n++)
		fputc(n, pFile);
	rewind(pFile);
	fread(buffer, 1, 26, pFile);
	fclose(pFile);
	buffer[26] = '\0';
	puts(buffer);
	return 0;
}

5. Text files and binary files

Depending on how the data is organized, data files are called text files or binary files .

Data is stored in binary form in memory, and if it is output to external storage without conversion, it is a binary file .

If it is required to store in the form of ASCII code on the external storage, it needs to be converted before storage. A file stored in the form of ASCII characters is a text file .

How is a piece of data stored in memory?

Characters are all stored in ASCII form, and numeric data can be stored in either ASCII or binary form.

If there is an integer 10000, if it is output to the disk in the form of ASCII code, it will occupy 5 bytes (one byte for each character) on the disk, and output in binary form, it will only occupy 4 bytes on the disk (VS2013 test ).

Test code:

#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;
}

6. Judgment of the end of file reading

6.1 misused feof 

Keep in mind: During the file reading process, the return value of the feof function cannot be used to directly determine whether the file is over.

 The function of feof is: when the file reading ends, judge whether the reason for the end of reading is: the end of the file is encountered.

        1. Whether the reading of the text file is over, judge whether the return value is EOF ( fgetc ), or NULL ( fgets )

        For example:

                ○    fgetc judges whether it is EOF .

                ○    fgets judges whether the return value is NULL .

        2. Judging the end of reading the binary file, and judging whether the return value is less than the actual number to be read.

        For example:

                ○   fread judges whether the return value is less than the actual number to be read.

Correct usage:

Example of a text file:

#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);
}

Example of a binary file:

#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);
}

7. File buffer

The ANSIC standard uses the " buffer file system " to process data files. The so-called buffer file system means that the system automatically creates a "file buffer " in the memory for each file being used in the program. Data output from memory to disk will be sent to the buffer in memory first, and then sent to disk together after the buffer is filled. If data is read from the disk to the computer, the data read from the disk file is input to the memory buffer (full of the buffer), 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.

#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
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;
}

A conclusion can be drawn here :

Because of the existence of the buffer, when the C language operates the file, it needs to refresh the buffer or close the file at the end of the file operation.

Failure to do so can cause problems reading and writing files.

Guess you like

Origin blog.csdn.net/m0_73156359/article/details/131963751