C language: file operation

 

catalogue

1, Classification of documents

2, File pointer

3, Open and close files

4, How to read and write files

1. Sequential reading and writing of documents

1. fputs write file

2. fgetc reads files

3. fputs write file

4. fgets reading files

5. fprintf write formatted data

6. fscanf read formatted data

7. fwrite binary write file

8. fread binary read file

2. Random reading and writing of documents

1. fseek

2. ftell

3. rewind

5, Text and binary files

6, Determination of the end of file reading

7, File buffer

1, Classification of documents

In programming, according to the perspective of file function, we generally talk about two kinds of files: program file and data file.

1. Program files include source program files (i.e. c files), target files (obj files in Windows Environment) and executable programs (exe files in Windows Environment).

2. Data file: the file content 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.

The above is only the basic concept of program file and data file, but in practice, we don't say that we must distinguish program file and data file in this way, because sometimes a program file reads the data file, which is actually a program file. According to the concept, it should be a program file, but it is the Party of the read data, Then it's a data file again, so in practice, it won't distinguish program files from data files. It's OK to have a basic understanding.

2, File pointer

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

Each used FILE opens up a corresponding FILE information area in the memory to store the relevant information of the FILE (such as the name of the FILE, the status of the FILE, the current location of the FILE, etc.). This information is stored in a structure variable. The structure type is declared by the system and named FILE. Whenever a FILE is opened, the system will automatically create a variable of FILE structure according to the situation of the FILE, and fill in the information in it. These relevant details are unknown to our users and do not need to be understood.

We usually maintain the variables of this FILE structure through a pointer to FILE. For example, we define a pointer variable PF, which points to FILE type data. When we want to open a FILE, we can make pf point to the FILE information area of the FILE (a structure variable), The FILE can be accessed through the information in the FILE information area (in other words, the FILE associated with it can be found through the FILE pointer variable).

3, Opening and closing of files

The FILE should be opened before reading and writing, and closed after use. Among them, ANSIC stipulates to use fopen function to open the FILE and fclose function to close the FILE. In addition, when writing a program to open a FILE, it will return a pointer variable of FILE * to point to the FILE, which also establishes the relationship between the pointer and the FILE.

Here is a table of file opening methods:

File usagemeaningIf the specified file does not exist
"r" (read only)To enter data, open an existing text fileerror
"w" (write only)To output data, open a text fileCreate a new file
"a" (added)Add data to the end of a text fileCreate a new file
"rb" (read only)To enter data, open a binary fileerror
"wb" (write only)To output data, open a text fileCreate a new file
"ab" (additional)Add data to the end of a binary fileerror
"r +" (read / write)To read and write, open a text fileerror
"w +" (read / write)Create a new file for reading and writingCreate a new file
"a +" (read-write)Open a file and read and write at the end of the fileCreate a new file
"rb +" (read and write)Open a binary file for reading and writingerror
"wb +" (read / write)Create a new binary file for reading and writingCreate a new file
"ab +" (read and write)Open a binary file and read and write at the end of the fileCreate a new file

It should be noted here that: output refers to outputting the data in memory to the screen or file; Input is to input the data typed by the keyboard or the data in the file into memory.

4, How to read and write files

1. Sequential reading and writing of documents

The following lists the related functions of sequential file reading and writing, and then realizes them one by one through examples:

Function namefunctionApply to
fgetcCharacter input functionAll input streams
fputcCharacter output functionAll output streams
fgetsText line input functionAll input streams
fputsText line output functionAll output streams
fscanfFormat input functionAll input streams
fprintfFormat output functionAll output streams
freadBinary inputfile
fwriteBinary outputfile

1. fputs write file

It is not difficult to see from the data that the first parameter is a character pointer, and the second parameter represents a stream. for instance:

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	char ch = '0';
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		fputc(ch, pf);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

2. fgetc reads files

fgetc has only one parameter, but one thing is the same as fputs, that is, the character pointed to by this function will automatically move back one character every time it is called. for instance:

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c", ch);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

It should be noted here that when we define ch, we should define it as int type, because if we find null (i.e. end), fgetc will return EOF, and the value of EOF is - 1. Only int type can represent the value of - 1.

3. fputs write file

The fputs function is basically the same as the fputc function, except that one line can be written directly to the file, which is still applicable to all output streams. for instance:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fputs("hello\n", pf);
	fputs("world\n", pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

4. fgets reading files

The fgets function is different from fgetc.

 

The first parameter is a self-defined array, which is used to store the data obtained from the file. The second parameter is the number of characters to be obtained (but actually num-1 characters are returned), and the third parameter is the stream. Among them, if the first line is not fully filled, the second call to fgets function will not be directly replaced with the second line, but will continue to obtain the remaining characters in the first line until '\ 0', and the next call will not wrap the line. for instance:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	char buf[1000] = { 0 };
	fgets(buf, 8, pf);
	printf("%s", buf);
	fgets(buf, 3, pf);
	printf("%s", buf);
	return 0;
}

5. fprintf write formatted data

The fprintf function is used to write formatted data, and it is also suitable for all output streams.

 

The parameter form of fprintf function is similar to that of printf function, except that an additional stream is added in front to write formatted data. For example:

#include <stdio.h>
#include <string.h>
#include <errno.h>

struct Stu
{
	char name[10];
	int age;
	float d;
};

int main()
{
	struct Stu s = { "Zhang San",20,88.5 };
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fprintf(pf, "%s %d %f", s.name, s.age, s.d);
	fclose(pf);
	pf = NULL;
	return 0;
}

6. fscanf read formatted data

fscanf function is a pair of fprintf function, which is also similar to scanf function. Its function is to read formatted data, which is also applicable to all input streams. for instance:

#include <stdio.h>
#include <string.h>
#include <errno.h>

struct Stu
{
	char name[10];
	int age;
	float d;
};

int main()
{
	struct Stu s = { 0 };
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.d));
	printf("%s %d %f", s.name, s.age, s.d);
	fclose(pf);
	pf = NULL;
	return 0;
}

7. fwrite binary write file

 

fwrite function writes files in binary mode. The first parameter is the array of incoming data, the second parameter is the size of each element in the array, the third parameter is the number of elements to be written, and the fourth parameter is the stream. However, it only applies to files and not to other output streams. for instance:

#include <stdio.h>
#include <string.h>
#include <errno.h>

struct Stu
{
	char name[10];
	int age;
	float d;
};

int main()
{
	struct Stu s[2] = { {"Zhang San",20,88.5} , {"Li Si",50,99.5} };
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fwrite(s, sizeof(struct Stu), 2, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

8. fread binary read file

 

The fread function and the fwrite function are a pair, and they are only applicable to files. for instance:

#include <stdio.h>
#include <string.h>
#include <errno.h>

struct Stu
{
	char name[10];
	int age;
	float d;
};

int main()
{
	struct Stu s[2] = { 0 };
	FILE* pf = fopen("data.txt", "rb");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fread(s, sizeof(struct Stu), 2, pf);
	for (int i = 0; i < 2; i++)
	{
		printf("%s %d %f\n", s[i].name, s[i].age, s[i].d);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

Here, I'll introduce most of the common functions of sequential reading and writing files. But one thing to note: the streams mentioned above are customized, but in C language programs, as long as they run, three streams will be opened by default: 1 Stdin -- standard input stream (for example, scanf is one of them); 2. stdout -- standard output stream (for example, printf is one of them); 3. stderr -- standard error flow.

Summarize and compare a set of functions: scanf/fscanf/sscanf and printf/fprintf/sprintf

1. scanf is a function that formats input from standard input stream (stdin); printf is an output function that formats the standard output stream (stdout).

2. fscanf can read formatted data from standard input stream (stdin) / specified file stream; fprintf outputs the data in a formatted manner to the standard output stream (stdout) / specified file stream

3. sscanf can extract (convert) formatted data from a string; sprintf converts a formatted data into a string

2. Random reading and writing of documents

1. fseek

The fseek function locates the file pointer according to the position and offset of the file pointer. The first parameter is the stream, the second parameter is the offset, and the third parameter is the position pointed by the pointer (which can be defined at the beginning, current and end respectively). For example:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	int ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	fseek(pf, 3, SEEK_CUR);
	ch = fgetc(pf);
	printf("%c\n", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

For this function, no matter reading or writing files, you can "hit where you mean".  

2. ftell

The ftell function returns the offset of the file pointer from the starting position. Parameters only need to flow (Note: the return value of this function is of type long int). for instance:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fseek(pf, 0, SEEK_END);
	printf("%ld\n", ftell(pf));
	fclose(pf);
	pf = NULL;
	return 0;
}

3. rewind

The rewind function returns the position of the file pointer to the initial position of the file. Parameters only need to flow, for example:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fseek(pf, 0, SEEK_END);
	rewind(pf);
	printf("%ld", ftell(pf));
	return 0;
}

5, Text and binary files

According to the organization form of data, data files are called text files or binary files.

1. Data is stored in binary form in memory. If it is output to external memory without conversion, it is a binary file

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

Here we need to explain: characters are stored in ASCII form in memory; Numerical data can be stored in ASCII form or binary form.

6, Determination of the end of file reading

A mistake many people make is that in the process of reading a file, the return value of the feof function cannot be directly used to judge whether the file ends.

The correct usage of this function should be applied to judge whether the reading fails or the end of the file is encountered when the file reading ends.

For example:

1. If the reading of text file ends normally, judge whether its return value is EOF and the latter is NULL (fgetc judges whether it is EOF; fgets judges whether it is NULL)

2. Whether the reading of binary files ends normally, it is necessary to judge whether the return value is less than the actual number to be read (such as fread)

Here is an example of text file and binary file:

Text file:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c", ch);
	}
	if (ferror(pf))
	{
		printf("I/O error when reading\n");
	}
	else if (feof(pf))
	{
		printf("End of file reaches successfully\n");
	}
	return 0;
}

Binary file:

#include <stdio.h>
#include <string.h>
#include <errno.h>
enum
{
	SIZE = 5
};
int main()
{
	double a[SIZE] = { 1.,2.,3.,4.,5. };
	//Write a binary file
	FILE* pf = fopen("data.txt", "wb");
	fwrite(a, sizeof(*a), SIZE, pf);
	fclose(pf);
	pf = NULL;
	double b[SIZE];
	pf = fopen("data.txt", "rb");
	size_t ret = fread(b, sizeof(*b), SIZE, pf);
	if (ret == SIZE)
	{
		printf("Array read successfully\n");
		for (int n = 0; n < SIZE; ++n)
		{
			printf("%f ", b[n]);
		}
	}
	else
	{
		if (feof(pf))
		{
			printf("Error reading data.txt:unexpected end of file\n");
		}
		else if (ferror(pf))
		{
			printf("Error reading data.txt\n");
		}
	}
	return 0;
}

7, File buffer

ANSIC standard adopts "buffer file system" to process data files. In fact, file buffer system refers to that the system automatically opens up a "file buffer" for each file being used in the program in memory. 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 you read data from the disk to the computer, read the data from the disk file, input it into the memory buffer (fill the buffer), and then send the data from the buffer to the program data area (program variables, etc.)

Summary: because of the existence of file buffer, C language needs to refresh the buffer or close the file at the end of file operation when operating the file; Otherwise, it may cause problems in reading and writing files.  

Keywords: C Back-end

Added by plus2net on Fri, 25 Feb 2022 11:33:10 +0200