The strongest C language tutorial in history -- file operation

Posted by FUEL on Mon, 31 Jan 2022 08:24:59 +0100

catalogue

(4)fputs()

(5)fprintf()

(6)fscanf()

(7)fwrite() 

(8)fread()

4.1 comparing a set of functions

4.1.1 understand sscanf() and sprintf() functions

5. Random reading and writing of documents

5.1 fseek()

5.2 ftell()

5.3 rewind() 

6. Text files and binary files

7. Determination of the end of file reading

7.1 misused feof

8. File buffer

8.1 what is a file buffer

8.2 significance of buffer zone

8.3 classification of buffer zones

(4)fputs()

Function: write a string to the file stream

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

Screenshot of file after operation:

Note: the fputs() function does not automatically carry a newline character

Examples of direct application of functions fgets() and fputs():

#include<stdio.h>
int main()
{
	//Read a line of information from the keyboard
	char buf[1024] = { 0 };
	fgets(buf, 1024, stdin);//Read from standard input stream
	fputs(buf,stdout);//Output to standard output stream
	//The two lines above are equivalent to the two lines below
	//gets(buf);
	//puts(buf);
   
return 0;
}

Operation screenshot:

A newline character appears above because we entered a newline character at the end of the input.

(5)fprintf()

Compare printf()

Use examples:

#include<stdio.h>
#include<string.h>
#include<errno.h>
struct S
{
	int n;
	float score;
	char arr[10];
};
int main()
{
	struct S s = { 100,3.14f,"bit" };
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fprintf(pf, "%d %f %s", s.n, s.score, s.arr);
   fclose(pf);
   pf = NULL;    
	return 0;
}

Screenshot after operation:

(6)fscanf()

Compare scanf()

Use examples:

#include<stdio.h>
#include<string.h>
#include<errno.h>
struct S
{
	int n;
	float score;
	char arr[10];
};
int main()
{
	struct S s = {0};
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	fscanf(pf, "%d %f %s", &s.n, &s.score, &s.arr);
	printf("%d %f %s", s.n, s.score, s.arr);
	fclose(pf);
	pf = NULL;
	return 0;
}

Operation screenshot:

Examples of direct application of functions fprintf() and fscanf():

#include<stdio.h>
struct S
{
	int n;
	float score;
	char arr[10];
};
int main()
{
	struct S s = {0};
	fscanf(stdin, "%d %f %s", &s.n, &s.score, &s.arr);
	fprintf(stdout, "%d %f %s", s.n, s.score, s.arr);
	return 0;
}

Operation screenshot:

(7)fwrite() 

buffer: pointer to the written data

Size: the size of the element to be written, in bytes

count: the number of data written

Stream: destination stream written

Use examples:

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	double score;
};
int main()
{
	struct S s = { "Zhang San",20,55.6 };
	FILE* pf = fopen("text.txt", "wb");
	if (pf == NULL)
	{
		return 0;
	}
	//Write files in binary form
	fwrite(&s, sizeof(struct S), 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

(8)fread()

buffer: the location where data is stored

Size: the size of the element

count: number of read elements

stream: the file structure pointed to by the pointer

Use examples:

#include<stdio.h>
struct S
{
	char name[20];
	int age;
	double score;
};
int main()
{
	struct S tmp = { 0 };
	FILE* pf = fopen("text.txt", "rb");
	if (pf == NULL)
	{
		return 0;
	}
	//Read files in binary form
	fread(&tmp, sizeof(struct S), 1, pf);
	printf("%s %d %lf", tmp.name, tmp.age, tmp.score);
	fclose(pf);
	pf = NULL;
	return 0;
}

Operation screenshot:

4.1 comparing a set of functions

scanf/fscanf/sscanf printf/fprintf/sprintf

4.1.1 understand sscanf() and sprintf() functions

(1)sscanf()

Function Description: read a piece of formatted data from a string.

Use examples:

#include<stdio.h>
struct S
{
	int n;
	float score;
	char arr[10];
};
int main()
{
	struct S s = { 100,3.14,"hello"};
	struct S tmp = { 0 };
	char buf[1024] = { 0 };
   //Convert the formatted data into a string and store it in buf
	sprintf(buf, "%d %f %s", s.n, s.score, s.arr);
   //Read the formatted data from buf to tmp
	sscanf(buf, "%d %f %s", &(tmp.n), &(tmp.score), &(tmp.arr));
	printf("%d %f %s\n", tmp.n, tmp.score, tmp.arr);
	return 0;
}

Operation screenshot:

(2)sprintf()

Function Description: write the formatted data into a string.

Use examples:

#include<stdio.h>
struct S
{
	int n;
	float score;
	char arr[10];
};
int main()
{
	struct S s = { 100,3.14,"hello"};
	char buf[1024] = { 0 };
	sprintf(buf, "%d %f %s", s.n, s.score, s.arr);
	printf("%s", buf);
	return 0;
}

scanf/printf is a formatted input / output statement for standard input / output streams.

fscanf/fprintf is a formatted input / output statement for all input streams / all output streams, including the functions of the above functions.

sscanf/sprintf sscanf reads the formatted data from the string, and sprintf outputs (stores) the formatted data into a string.

5. Random read file

5.1 fseek()

Function: move the file pointer to a specific location

stream: file pointer to move

Offset: offset (can be negative, integer is offset to the right, negative is offset to the left)

origin: the current position of the file pointer

Three choices of orifon starting position:

SEEK_CUR: current position of the file pointer

SEEK_END: the end position of the file (after the last character, for example, after f in the following example)

SEEK_SET: the starting position of the file

Use examples:

Initial screenshot of file:

#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//1. Locate file pointer
	fseek(pf, 2, SEEK_CUR);
	//2. Read the file
	int ch = fgetc(pf);
	printf("%c", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

Operation screenshot:

5.2 ftell()

Function: calculate the offset of the file pointer relative to the starting position

Use examples:

#include<stdio.h>
#include<errno.h>
#include<string.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//1. Locate file pointer
	fseek(pf, 2, SEEK_CUR);
	//2. Calculate offset
	int pos = ftell(pf);
	printf("%d\n", pos);
	fclose(pf);
	pf = NULL;
	return 0;
}

Operation screenshot:

Note: after the fgetc() function reads the file pointer, it will automatically shift back by one bit

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

Operation screenshot:

5.3 rewind() 

Function: return the file pointer to the starting position of the file (for example, the offset of the starting position of the file is 0).

Use examples:

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

Operation screenshot:

6. Text and binary files

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

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

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.

How is a data stored in memory?

All characters are stored in ASCII form, and numerical data can be stored in ASCII form 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 in 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).

Storage form of 10000 in memory: 10 27 00 00 00 (displayed in hexadecimal form)

Test code:

#include <stdio.h>
int main()
{
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	fwrite(&a, 4, 1, pf);//Write to file in binary form
	fclose(pf);
	pf = NULL;
	return 0;
}

7. Determination of the end of file reading

7.1 misused feof

Keep in mind: in the process of file reading, the return value of feof function cannot be directly used to judge whether the file ends. It is used to judge whether the reading fails or the end of the file is encountered when the file reading ends.

1. Whether the reading of text file is finished, judge whether the return value is EOF (fgetc) or NULL (fgets). If so, return a value other than 0. For example, fgetc determines whether it is EOF, and fgets determines whether the return value is NULL

2. Judge the reading end of binary files, and judge 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.

Examples of correct use of text files:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int c; // Note: int, not char, requires EOF processing
    FILE* fp = fopen("test.txt", "r");
    if (!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
    }
    //fgetc will return EOF when reading fails or when the file ends
    while ((c = fgetc(fp)) != EOF) // Standard C I/O read file cycle
    {
        putchar(c);
    }
    //Judge why it ended
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

Examples of binary files:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
    double a[SIZE] = { 1.,2.,3.,4.,5. };
    FILE* fp = fopen("test.bin", "wb"); // Binary mode must be used
    fwrite(a, sizeof * a, SIZE, fp); // Write array of double
    fclose(fp);
    double b[SIZE];
    fp = fopen("test.bin", "rb");
    size_t ret_code = fread(b, sizeof * b, SIZE, fp); // Read the array of 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);
}

8. File buffer

8.1 what is a file buffer

ANSIC standard uses "buffer file system" to process data files. The so-called buffer file 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.) one by one. The size of the buffer is determined by the C compilation system.

 

#include <stdio.h>
#include <windows.h>
//VS2013 WIN10 environment test
int main()
{
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//Put the code in the output buffer first
	printf("Sleep for 10 seconds-The data has been written. Open it test.txt File, no content found in the file\n");
	Sleep(10000);
	printf("refresh buffer \n");
	fflush(pf);//When the buffer is refreshed, the data of the output buffer is written to the file (disk)
	//Note: fflush cannot be used on higher version VS
	printf("Sleep for another 10 seconds-At this point, open again test.txt File, the file has content\n");
	Sleep(10000);
	fclose(pf);
	//Note: fclose also flushes the buffer when closing the file
	pf = NULL;
	return 0;
}

Here we can draw a conclusion: because of the existence of buffer, C language needs to refresh the buffer or close the file at the end of file operation when operating the file. If not, it may cause problems in reading and writing files.

8.2 significance of buffer zone

Firstly, transmitting several characters as a block saves time than sending characters one by one; Secondly, if the user types the wrong character, he can modify the error directly through the keyboard. When the Enter key is finally pressed, the correct input is sent.

8.3 classification of buffer zones

C language uses different buffers in different places according to needs.

Buffers are divided into two categories: fully buffered I/O and line buffered I/O and unbuffered I/O.

(1) Full buffering means that the buffer is refreshed only when the current buffer is full (the content is sent to the destination), which usually appears in the file input. The size of the buffer depends on the system, and the common sizes are 512 bytes and 4096 bytes.

(2) Line buffering refers to refreshing the buffer when a line break occurs. Keyboard input is usually line buffered input, so the buffer is refreshed when you press Enter. A common example is the getchar() function. When the program calls the getchar() function, the program waits for the user to press the key, and the characters entered by the user are stored in the keyboard buffer until the user presses Enter (the Enter character is also placed in the buffer). The getchar() function starts reading one character at a time from the keyboard buffer after the user types a carriage return. In other words, subsequent getchar() function calls will not wait for the user to press the key, but directly read the characters in the buffer, and wait for the user to press the key again until the characters in the buffer are read. When the buffer is full, it will not be refreshed automatically and input cannot be continued. You need to press Enter to refresh the buffer.

(3) Unbuffered: standard output unbuffered (for example: cerr)

(4) Buffer flush (performing real I/O operations)

When the buffer is full: execute the flush statement; Execute the end statement; Close the file.

Topics: C Back-end