This is the 16th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

File operations

File operation is not used much in practical work. But C is incomplete without it. So this time we will look at C language file operation.

Definition of file

Storing data in external storage (writing to a file) prevents data loss after each program is finished and loads data into memory while the program is running, which is why files exist.

In the program design, from the point of view of file function classification, generally speaking of the file has two kinds: program file and data file.

  • Program files: files related to the program, such as source file. C, target file generated by compilation. Obj, executable program. Exe, etc.

  • Data file: a file, such as.txt, that stores the read and write data of the program when it is running.

Note that operations between data files and program files are called reads and writes. Taking a program as an object, the outward modification of data or output content is called write, and the acquisition of data from a data file to a program file is called read. While writing is output, reading is called input.

What is different is that the data input and output objects are changed from terminals to files. For example, printf and scanf output data to the screen and input data from the keyboard respectively. Now we can replace the screen and keyboard with files, and input and output files.

The files discussed in this chapter are data files.

The file name

Each file has and only one unique file id that describes the file. The file identifier consists of three parts: file path + file name trunk + file suffix.

For example, D:\code\data.txt. For convenience, the file id is usually the file name. As shown in figure:

 

The file type

Depending on how the data is organized, data files are divided into two types: text files or binary files.

  • Binary file: Data is stored in memory in binary form and then directly output to external memory, called binary file.
  • Text file: Data is converted to ASCII code and stored in external memory.

As shown in the figure above, test.c is a text file if it can be understood, while *. Exe is a binary file if it shows garbled characters when opened.

Storage of data

When data is stored in memory, characters are stored as ASCII codes, and values can be stored as ASCII codes or binary codes.

For example, the value is an integer 10000. If it is stored in ASCII format, five characters require five bytes in total. If it is stored in binary form, it is converted to complement code. Integer data takes 4 bytes altogether.

Use the following code to store 10000 in binary form to the file data.txt.

int main(a) {
	FILE* pf = fopen("data.txt"."wb");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	int a = 10000;
	fwrite(&a, 4.1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}
Copy the code

We use the binary editor to look at the 10000 files written in binary form, we can see the following phenomenon: the answer can be deduced as follows.

/ / 1.
00000000 00000000 00100111 00010000 - 10000The original code//2.c
00010000 00100111 00000000 00000000- Small - end storage/ / 3.
1   0    2   7    0   0    0   0- Convert to hexadecimal10 27 00 00
Copy the code

 

File buffer

The C standard specifies the use of a “buffered file system” to process data files. A buffered file system automatically creates a “file buffer” ** for each file used by a program.

  1. Output data from memory to external memory passes through the output buffer, which is filled before it is sent to external memory together. In the same way,
  2. Input data from external memory to memory will pass through the input buffer, fill the input buffer and then input to memory together.

The size of the buffer is determined by the compilation system, and the specific number is “full”, which is not further studied in THE C language stage.

The transfer of data between the two is accomplished by the program calling the input and output interfaces provided by the operating system. The goal is not to interrupt the operating system with frequent transmissions.

 

File information area

In buffered file systems, a key concept is called file type pointer, or file pointer for short.

When a program operates on a file, it creates a file information area in memory corresponding to the file, which is used to store the file information (such as file name, status, location, etc.). This information is a member of a structure whose type is declared by the system and named “FILE”.

When each file is operated, a file information area will be created first. The so-called file information area is actually a variable created by a encapsulated structure type, which is strongly associated with the owning file. Operating file is actually operating file information area, open the file actually returns the address of the file information area. As shown in figure:

From the memory reading way can also pry, the memory data is also read level by level, the first memory data to the cache, and then put in the register. Read the file is also such logic, otherwise directly read the entire file, load slow occupy large error prone.

Vs2013 can still see that the structure of the file information area encapsulates the content, which can be seen as the relevant information of the file. The FILE information area is a structure variable of type FILE.

The file pointer

These variables are automatically created by the system, so you don’t have to worry about the details. The FILE structure variable is typically maintained through a pointer to FILE*, which is the FILE pointer.

FILE* pf;// A pointer to the file information area
Copy the code

The structure pointer variable PF of type FILE points to a FILE information area to manipulate the FILE. As shown in figure:

 

Switch operation of files

To operate on a file using a file pointer, you must first open the file and then close it. To operate a file, perform the following steps: 1. Open the file 2. Read and write the file 3.

The C language standard specifies the use of fopen and fclose to open and close files.

File openingfopen

Function declaration
FILE* fopen (const char* filename, const char* mode);
Copy the code
Return Value
This function returns a pointer to the open file. A null pointer value indicates an error. 

Parameters
1. filename - Filename
2. mode - Type of access permitted

Remarks
The fopen function opens the file specified by filename.
Copy the code

The fopen function opens a file named filename in mode and returns the starting address of the file’s information area.

The usage function
  • Open the file in read or write mode bymodeDecision. The opening mode is as follows:
model way meaning note
“r” read-only Enter the data and open the existing text file If the file does not exist, the call fails
“w” Just write Output the data and “create” a text file If the file already exists, destroy the content
“a” additional Output data, adding data to the end of the text file If the file does not exist, create a file
“rb” read-only Enter the data and open the existing binary file If the file does not exist, the call fails
“wb” Just write Output the data and “create” a binary file If the file already exists, destroy the content
“ab” additional Output data, adding data to the end of the binary If the file does not exist, create a file
“r+” Read and write Both input and output, open an existing text file If the file does not exist, the call fails
“w+” Read and write Both input and output, “new” a text file If the file already exists, destroy the content
“a+” Read and Add data to the end of a text file, both input and output If the file does not exist, create a file
.
  • The file namefilenameThe relative path is the folder in the solution directory, and the absolute path is the file path + file name trunk + suffix.
// Open the file
//1. Absolute path
FILE* pf = fopen("C:\\Users\\w3395\\Desktop\\data.txt"."w");
//2. Relative path
FILE* pf = fopen("data.txt"."w");
Copy the code

File closingfclose

Function declaration
int fclose (FILE* stream);
Copy the code
Return Value
fclose returns 0 if the stream is successfully closed.

Parameter
1. stream - Pointer to FILE structure

Remarks
The fclose function closes stream.
Copy the code

The fclose function closes the input and output streams to the file information area.

The usage function
  • fcloseOnly the input/output stream on the file is closed; the file pointer is not null. To prevent wild Pointers, empty the file pointer.
int main(a) {
	// Open the file
	FILE* pf = fopen("data.txt"."w");
	// Failed to open
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	// Manipulate files
	/ /...
	// Close the file
	fclose(pf);
	pf = NULL;
	return 0;
}
Copy the code

 

Read and write operations on files

The definition of the flow

“A stream is the source or destination of data stored on a disk or other peripheral device” — C Programming

A stream is a logical concept. The one that produces data is called an input stream, and the one that consumes data is called an output stream. Production and consumption vary from device to device, but C treats them equally, using the word “flow” instead.

Characters are placed in files or printed to screens, which are external devices. Screens, networks, files, and hard drives are all external devices. Different devices must have different read and write modes. For convenience, the concept of “flow” is abstracted and the character “flow” is used to summarize their characteristics. Therefore, a stream can be regarded as a data carrier through which data can be exchanged and transmitted. The way of transmitting data is determined by the “stream”. We simply put the data into the stream.

Programs interact with data in the form of “streams.” When data is exchanged between objects, the data is first converted into some form of stream, and then transmitted through the stream. After reaching the target object, the stream is converted into object data. When reading and writing files in C language, open file operation is performed first. This operation is to open data stream, and close file operation is to close data stream.

When we use printf,scanf we are passing the standard I/O stream between the on-screen keyboard and the program. There are three types of streams: stdout, stdin, and stderr, all of which are Pointers to FILE*.

Sequential reads and writes to files

The following are a pair of sequential read and write operations for different types of data. All output streams include file output streams and standard output streams.

The function name function Scope of application
fgetc Character input function All input streams
fputc Character output function All output streams
fgets Text line input function All input streams
fputs Text line output function All output streams
fscanf Formatting input function All input streams
fprintf Formatting output function All output streams
fread Binary input file
fwrite Binary output file

Character input outputfputc&fgetc

Function declaration
int fputc (int c, FILE* stream);
Copy the code
Return Value This function returns the character written. Parameters 1. c - Character to be written 2. stream - Pointer to FILE structure Remarks This function writes the single character c to a file at the position pointed by the Associated file position pointer (if defined) and advances the pointer appropriately.Copy the code
int fgetc (FILE* stream);
Copy the code
Return Value fgetc return the character read as an int or return EOF to indicate an error or end of file. Parameter stream - Pointer to FILE structure Remarks This function reads a single character from the current position of a file; The function then increments The associated file pointer (if defined) to point to The next character.Copy the code

Fputc puts the character C into the file pointed to by the file pointer stream.

Fgetc returns the character pointed to by the file pointer.

The usage function
  • fputcThe file pointer moves backward one character for each character written.fgetcThe file pointer moves backward one character for each character read.
  • fputcApplies to all output streams and can be output to any device.fgetcThe same applies to all input streams and data can be read from any device.
int main(a) {
	FILE* pf = fopen("data.txt"."w");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);	
	fclose(pf);
	pf = NULL;
	return 0;
}
int main(a) {
	FILE* pf = fopen("data.txt"."r");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	int ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	ch = fgetc(pf);
	printf("%c ", ch);
	fclose(pf);
	pf = NULL;
	return 0;
} 
Copy the code
// Standard output stream
fputc('b'.stdout);
fputc('i'.stdout);
fputc('t'.stdout);
// Standard input stream
printf("%c\n", fgetc(stdin));
printf("%c\n", fgetc(stdin));
printf("%c\n", fgetc(stdin));
Copy the code

String input outputfputs&fgets

Function declaration
int fputs (const char* string, FILE* stream);
Copy the code
Return Value This function returns a nonnegative Value if it is successful. On an error, fputs returns EOF. Parameters 1. string - Output string 2. stream - Pointer to FILE structure Remarks This function copies string to the output stream at the current position.Copy the code
char* fgets (char* string.int n, FILE* stream);
Copy the code
Return Value This function returns string. NULL is returned to indicate an error or an end-of-file condition. Parameters  1. string - Storage location for data 2. n - Maximum number of characters to read 3. stream - Pointer to FILE structure  Remarks The fgets function reads a string from the input stream argument and stores it in string. fgets reads characters from the current stream position to and including the first newline character, to the end of the stream, Or until the number of characters read is equal to n -- 1, whichever comes first. The result stored in string is appended with a null character. The newline character, if read, is included in the string.Copy the code

Fputc puts the string string into the file pointed to by the file pointer stream.

Fgets puts the first n-1 characters of the string pointed to in the stream file into the string and returns it as a return value.

The usage function
  • fputsWrite one line at a time, if newline is needed\nThe file pointer moves to the end.
  • fgetsOnly a specified number of characters are read at a time
    n 1 n-1
    The last character is the first character
    n n
    Characters for\ 0As the end of the string.

  • fputsApplies to all output streams and can be output to any device.fgetsThe same applies to all input streams and data can be read from any device.
int main(a) {
	FILE* pf = fopen("data.txt"."w");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	fputs("hello world! \n", pf);
	fputs("hello bit! \n", pf);
	fclose(pf);
	pf = NULL;
	return 0;
}
int main(a) {
	FILE* pf = fopen("data.txt"."r");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	char arr[20] = { 0 };
	fgets(arr, 5, pf);
	printf("%s\n", arr);
	fgets(arr, 5, pf);
	printf("%s\n", arr);
	fclose(pf);
	pf = NULL;
	return 0;
}
Copy the code

Formatting input outputfprintf&pscanf

Function declaration
int fprintf (FILE* stream, const char* format [, argument ]...);
Copy the code
Return Value fprintf returns the number of bytes written. This function returns a negative value instead when an output error occurs. Parameters 1. stream - Pointer to FILE structure 2. format - Format-control string 3. argument - Optional Arguments Fprintf formats(format) and prints all characters and values to the output stream. Each argument(parameter) is Converted and output according to the corresponding format specification. For fprintf, The format argument has the same syntax that it has in printf.Copy the code
int fscanf (FILE* stream, const char* format [, argument ]...);
Copy the code
Return Value
This function returns the number of fields(字段数) successfully converted(转化) and assigned(分配); 

Parameters
1. stream - Pointer to FILE structure
2. format - Format-control string
3. argument - Optional arguments

Remarks
The fscanf function reads data from the current position of stream into the locations given by argument (if any). It has the same form and function as the format argument for scanf;
Copy the code

Fprintf,fscanf is formatted, for example: “%d,%f”,a,f, output input to all input/output streams.

The usage function
  • fprintf.fscanfAnd printf,scnaf arguments are only different with a file pointer in frontpf“, so write printf,scanf and add the file pointer at the top of the parameter listpf. Such as:
struct S {
	int a;
	char c;
	double d;
};
int main(a) {
	FILE* pf = fopen("data.txt"."w");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	struct S s = { 100.'w'.3.14 };
	fprintf(pf, "%d %c %lf", s.a, s.c ,s.d);

	return 0;
}
int main(a) {
	FILE* pf = fopen("data.txt"."r");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	struct S s = { 0 };
	fscanf(pf, "%d %c %lf", &s.a, &s.c, &s.d);
	printf("%d %c %lf", s.a, s.c, s.d);
	return 0;
}
Copy the code
  • fprintfApplies to all output streams and can be output to any device.fscanfThe same applies to all input streams and data can be read from any device.

There are single character, string, and arbitrary format characters, strings, and formatting input and output functions. But these are textual input/output functions, followed by binary input/output functions.

Binary input outputfwrite&fread

Function declaration
size_t fwrite (const void* buffer, size_t size, size_t count, FILE* stream);
Copy the code
Return Value fwrite returns the number of full items actually written. Parameters 1. buffer - Pointer to data to be Written (Pointer to data to be written) 2. size-item size in bytes(element width) 3. count-number of items to be written(element Number) 4. stream-pointer Remarks The fwrite function writes up to count items, of size length each, from buffer to the output stream. The file pointer associated with stream (if there is one) is incremented by the number  of bytes actually written.Copy the code
size_t fread (void* buffer, size_t size, size_t count, FILE* stream);
Copy the code
Return Value
fread returns the number of full items actually read, which may be less than count if an error occurs or if the end of the file is encountered before reaching count. 

Parameters
1. buffer - Storage location for data
2. size - Item size in bytes
3. count - Maximum number of items to be read
4. stream - Pointer to FILE structure

Remarks
The fread function reads up to count items of size bytes from the input stream and stores them in buffer. The file pointer associated with stream (if there is one) is increased by the number of bytes actually read.
Copy the code

The usage function
  • fwriteFrom thebufferThe location of thecountA size ofsizeIs written to the file in binary formstreamIn the.

  • freadFrom the filestreamIn thecountA size ofsizeThe element is read in binary formbufferIn the.

struct S {
	int a;
	char c[20];
	double d;
};
int main(a) {
	FILE* pf = fopen("data.txt"."wb");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	struct S s = { 100."yyx".3.14 };
	fwrite(&s, sizeof(s), 1, pf);
	return 0;
}
int main(a) {
	FILE* pf = fopen("data.txt"."rb");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	struct S s = { 0 };
	fread(&s, sizeof(s), 1, pf);
	printf("%d %s %lf", s.a, s.c, s.d);
	return 0;
}
Copy the code

Comparison of input and output functions

/ / 1.
scanf/fscanf/sscanf
/ / 2.
printf/fprintf/sprintf
Copy the code
The function name content note
scanf fromStandard input stream(keyboard) reads formatted data Omit the standard
fscanf fromAll input streamsRead Reads formatted data F: the file
sscanf fromstringTo read formatted data S: a string
printf Output formatted data toStandard output streamOn the screen Omit the standard
fprintf Output formatted data toAll output streamson F: the file
sprintf Output formatted data tostringIn the S: a string

int main(a) {
    //sprintf
    struct S s = { 100."yyx".3.14 };
	char arr[20] = { 0 };
	sprintf(arr, "%d%s%lf", s.a, s.c, s.d);
	printf("%s\n", arr);
	//sscanf
	sscanf(arr, "%d %s %lf", &s.a, s.c, &s.d);
	printf("%d %s %lf", s.a, s.c, s.d);
	return 0;
}
Copy the code

Sprintf outputs formatted data to a string, and sscanf inputs string data to the program (read in formatted form).

Random reads and writes to files

Random read/write: Changes the position of the file pointer randomly to perform read/write operations at a customized position.

Changing file Pointersfseek

Function declaration
int fseek (FILE* stream, long offset, int origin);
Copy the code
Return Value
If successful, fseek returns 0. Otherwise, it returns a nonzero value.

Parameters
1. stream - Pointer to FILE structure
2. offset - Number of bytes from origin
3. origin - Initial position

Remarks
The fseek function moves the file pointer (if any) associated with stream to a new location that is offset bytes from origin. 
Copy the code

Fseek relocates the file pointer by the offset from the starting position of the file pointer.

The usage function
  • The starting positionoriginThree values can be passed:SEEK_SET.SEEK_END.SEEK_CUR, corresponding to the start of the file, the end of the file and the current location of the file.

  • The file pointer offset is the result of subtracting two Pointers. Input/output functions also affect the current position of the file pointer.

‘f’ is offset by 4 from the start SEEK_SET and -8 from the end of the file SEEK_END.

  • fseekThe relocation function is just a pointer to a file and does not contain any input/output statements.
int main(a)
{
	FILE* pf = fopen("C:\\Users\\w3395\\Desktop\\data.txt"."r");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
    // Read characters
	printf("%c", fgetc(pf));//y
	fseek(pf, 1, SEEK_SET);
	printf("%c", fgetc(pf));//o
	fseek(pf, 2, SEEK_SET);
	printf("%c", fgetc(pf));//u
	fseek(pf, 3, SEEK_SET);
	printf("%c", fgetc(pf));//r
	fseek(pf, 2 -, SEEK_CUR);
	printf("%c", fgetc(pf));//u
	fseek(pf, 2 -, SEEK_CUR);
	printf("%c", fgetc(pf));//o
	fseek(pf, 2 -, SEEK_CUR);
	printf("%c", fgetc(pf));//y
    fclose(pf);
	pf = NULL;
	return 0;
}
Copy the code

Locating file pointerftell

Function declaration
long ftell (FILE* stream);
Copy the code
Return Value
ftell returns the current file position.

Parameter
stream - Target FILE structure

Remarks
The ftell function gets the current position of the file pointer (if any) expressed as an offset relative to the beginning of the stream.
Copy the code

Ftell returns the position of the current file pointer as an offset from the starting position.

The usage function
int main(a)
{
	FILE* pf = fopen("C:\\Users\\w3395\\Desktop\\data.txt"."r");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	fseek(pf, 3, SEEK_SET);
	int ret = ftell(pf);
	printf("%d\n", ret);
    return 0;
}
Copy the code

Resetting the file pointerrewind

Function declaration
void rewind (FILE* stream);
Copy the code
Return Value None Parameter stream - Pointer to FILE structure Remarks The rewind function repositions(reset) The FILE pointer associated with stream to the beginning of the file.Copy the code
The usage function
  • rewindRestores the file pointer to its initial state.

 

End of file judgment

Judgment of the return value of an input function

Similar to oJ, the method of multiple input, using the return value of scanf to determine:

while (scanf("%d", &n) ! = EOF)} { ; }Copy the code

Since the input in oJ is controlled by the system (similar to reading a file), EOF is returned at the end of reading. Therefore, the effect of multiple reads can be achieved by judging the return value of scanf in the loop judgment part.

The file input function has the same characteristic, and can also be judged by its return value to achieve the purpose of cyclic reading.

Input function Use the return value to determine
fgetc Returns the read character as an integer, on an error or at the end of the fileEOF
fgets Returns the string read, in case of an error or the end of the fileNULL
fscanf Returns the number of fields successfully read and converted, fails to read if the number of fields is smaller than the specified number, or returns if there are no fields0
fread Returns the actual number of elements read, if less than the argumentcountIt cannot be read again.

The concrete implementation is as follows:

//fgetc
int ch = 0;
while((ch = fgetc(pf)) ! = EOF) {printf("%c ", ch);
}
//fgets
char arr[2] [20] = { 0 };
while ((fgets(arr, 3, pf)) ! =NULL) {
    printf("%s\n", arr);
}
//fscanf
int ch = 0;
while (fscanf(pf, "%c", &ch) == 1) {
    printf("%c\n", ch);
}
//fread
int ch = 0;
while (fread(&ch, 1.1, pf) == 1) {
    printf("%c\n", ch);
}
Copy the code

Judge file endfeof

Feof is not used to determine if a file is finished reading. It is used to determine whether the end of the file is due to an error or the end of the file when the file is finished reading.

Function declaration
Return Value feof returns a nonzero value after the first read operation that attempts to read past the end of the file.  It returns 0 if the current position is not end of file. There is no error return.Copy the code
The usage function
int main(a)
{
	FILE* pf = fopen("data.txt"."r");
	if (pf == NULL) {
		perror("fopen");
		return - 1;
	}
	int ch = 0;
	while((ch = fgetc(pf)) ! = EOF) {printf("%c ", ch);
	}
	if (feof(pf)) {
		printf("\n%s\n"."end of file reached successfully");
	}
	if (ferror(pf)) {
		printf("\n%s\n"."unknowed error");
	}
	fclose(pf);
	pf = NULL;
	return 0;
}
Copy the code
  • feof: Indicates the end of a file.

A non-zero value is returned when the end of the file is encountered, and 0 is returned otherwise.

  • ferror: Indicates the end of the file to determine if it encountered an error.

Returns a non-zero value when an error is encountered, or 0 otherwise.