catalogue
Sequential reading and writing of files
Random reading and writing of files
3 functions for locating file pointer offset
What is a file
Files on disk are files.
But in programming, we generally talk about two kinds of files: program file and data file.
Program file
It includes source program files (suffix. c), object files (suffix. obj in windows Environment), and executable programs (suffix. exe in windows Environment).
data file
The content of the file is not necessarily the program, but the data read and written when the program runs, such as the file from which the program needs to read data or the file that outputs the content.
Before we learned about file operation, most of us have seen that the input and output of the processed data are targeted at the terminal, that is, input data from the keyboard of the terminal and display the operation results on the display.
In fact, sometimes we will output the information to the disk, and then read the data from the disk to the memory when necessary. What we deal with here is the files on the disk.
file name
A file should have a unique file ID so that users can identify and reference it.
The file name consists of three parts: file path + file name trunk + file suffix
For example: c:\code\test.txt
c:\code \: file path
test: File trunk
. test file suffix
For convenience, the file ID is often referred to as the file name
file type
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 ASCII code on external memory, it needs to be converted before storage. Files stored in ASCII characters are text files.
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 (VS2019 test).
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; }
After running:
Step 1:
Step 2:
The results are as follows:
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.
field name 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
For example, the stdio.h header file provided by the VS2008 compilation environment contains the following file type declarations:
struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE;
The FILE types of different C compilers contain different contents, but they are similar.
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. Users don't have to care about the details. Generally, the variables of the FILE structure are maintained through a FILE pointer, which is more convenient to use.
Next, we can create a pointer variable of FILE *:
FILE* pf;// File pointer variable
Definition PF is a pointer variable to data of type FILE. You can make pf point to the FILE information area (a structure variable) of a FILE. The FILE can be accessed through the information in the FILE information area. That is, the FILE associated with it can be found through the FILE pointer variable.
For example:
Opening and closing of files
The file should be opened before reading and writing, and closed after use.
When writing a program, when opening a FILE, a pointer variable of FILE * will be returned to point to the FILE, which is equivalent to establishing the relationship between the pointer and the FILE.
ANSIC specifies that fopen function is used to open the file and fclose is used to close the file.
FILE * fopen ( const char * filename, const char * mode );
int fclose ( FILE * stream );
The opening method is as follows:
For example, chestnuts:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "w"); //Open file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } fputs("hello world!", pf); fclose(pf); //Close file pf=NULL; return 0; }
Sequential reading and writing of files
The input stream represents a read file.
The output stream represents a write file.
fgetc
usage method:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "r"); //Open file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } char ch=fgetc(pf); printf("%c", ch); fclose(pf); //Close file pf=NULL; return 0; }
Operation results:
fgetc(pf); Pf stands for file pointer, which can read one character at a time.
fputc
usage method:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "w"); //Open file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } fputc('b', pf); fputc('i', pf); fputc('t', pf); fclose(pf); //Close file pf=NULL; return 0; }
After running, open the file under the corresponding project:
fputc('b', pf);
fputc('i', pf);
fputc('t', pf);
Writes characters to the file pointer.
fgets
usage method:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "r"); //Open file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } char arr[20] = { 0 }; fgets(arr, 20, pf); printf("%s", arr); fclose(pf); //Close file pf=NULL; return 0; }
char *fgets( char *string, int n, FILE *stream );
char *string: represents a pointer and can receive an address. Here we define an array and pass the array name.
int n: the maximum number of characters that can be read at a time.
FILE *stream: file pointer.
fputs
usage method:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "w"); //Open file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } fputs("hello word!", pf); fclose(pf); //Close file pf=NULL; return 0; }
int fputs( const char *string, FILE *stream );
const char *string: the string to write
FILE *stream: file pointer
After running the program, go to the current project directory to see the results:
fprintf
usage method:
#include<stdio.h> #include<stdlib.h> struct S { int n; double d; }; int main() { struct S s = { 10,3.14 }; FILE* pf = fopen("test.txt", "w"); //Open file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } //Write file fprintf(pf, "%d %lf", s.n, s.d); fclose(pf); //Close file pf=NULL; return 0; }
int fprintf( FILE *stream, const char *format [, argument ]...);
FILE *stream: file pointer
const char *format: member type% d% lf
argument]...:: variable, specific content
After running, come to the path of the project, and the results are as follows:
fscanf
usage method:
#include<stdio.h> #include<stdlib.h> struct S { int n; double d; }; int main() { struct S s = { 0 }; FILE* pf = fopen("test.txt", "r"); //Open file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } //read file fscanf(pf, "%d %lf", &(s.n), &(s.d)); printf("%d %lf", s.n, s.d); fclose(pf); //Close file pf=NULL; return 0; }
int fscanf( FILE *stream, const char *format [, argument ]... );
FILE *stream: file pointer
const char *format: member type
argument]...: variable
After running, the results are as follows:
fwrite
usage method:
#include<stdio.h> #include<stdlib.h> struct S { int n; double d; char name[10]; }; int main() { struct S s = { 10,3.14 ,"zhangsan" }; FILE* pf = fopen("test.txt", "wb"); //Write file in binary form if (pf == NULL) { printf("fopen fail\n"); exit(-1); } //Write file --- write file in binary form fwrite(&s, sizeof(s), 1, pf); fclose(pf); //Close file pf=NULL; return 0; }
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
const void *buffer: points to the written data
size_t size: the size of the written data, in bytes
FILE *stream: file pointer
Results of operation under the project:
Because this is a file written in binary form, you can't understand it with text.
fread
usage method:
#include<stdio.h> #include<stdlib.h> struct S { int n; double d; char name[10]; }; int main() { struct S s = { 0 }; FILE* pf = fopen("test.txt", "rb"); //Binary read file if (pf == NULL) { printf("fopen fail\n"); exit(-1); } //Read file --- read file in binary form fread(&s, sizeof(s), 1, pf); //Print printf("%d %lf %s", s.n, s.d, s.name); fclose(pf); //Close file pf = NULL; return 0; }
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
void *buffer: the place where data is received
size_t size: the size of data, in bytes
size_t count: the number of times the data is read, Maximum number of items to be read
Operation results:
sprintf
usage method:
#include<stdio.h> #include<stdlib.h> struct S { int n; double d; char name[10]; }; int main() { char arr[100] = { 0 }; struct S tmp = { 0 }; struct S s = { 100,3.14,"zhangsan" }; //Converts a formatted data into a string sprintf(arr, "%d %lf %s", s.n, s.d, s.name); //Print printf("%s", arr); return 0; }
int sprintf( char *buffer, const char *format [, argument] ... );
char *buffer: the place where the converted string is stored
const char *format: the type of formatted data to be converted
argument]...: format data
Operation results:
sscanf
usage method:
#include<stdio.h> #include<stdlib.h> struct S { int n; double d; char name[10]; }; int main() { char arr[100] = { 0 }; struct S tmp = { 0 }; struct S s = { 100,3.14,"zhangsan" }; //Converts a formatted data into a string sprintf(arr, "%d %lf %s", s.n, s.d, s.name); //Extract a formatted data from the string in the arr sscanf(arr, "%d %lf %s", &(tmp.n), &(tmp.d), tmp.name); //Print printf("%d %lf %s", tmp.n, tmp.d, tmp.name); return 0; }
int sscanf( const char *buffer, const char *format [, argument ] ... );
const char *buffer: the place where data is stored
const char *format: the type to convert to formatted data
argument ] ...: Optional arguments
The operation results are as follows:
be careful:
The results of sprintf and sscanf are the same, but the meaning is different.
The former prints strings, while the latter prints formatted data.
Compare a set of functions
scanf: reads formatted data from the standard input stream (keyboard).
fscanf: read formatted data from all inputs.
sscanf: read a formatted data from a string. / / convert a string into formatted data.
printf: output formatted data to standard output (screen).
fprintf: reads formatted data from all input streams.
sprintf: convert the formatted data into the corresponding string.
Random reading and writing of files
fseek
Locate the file pointer according to the position and offset of the file pointer.
int fseek( FILE *stream, long offset, int origin );
FILE *stream: file pointer name
long offset: offset relative to the starting position
int origin: the default starting position
usage method:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "rb"); if (pf == NULL) { printf("fopen fail\n"); exit(-1); } fseek(pf, 2, SEEK_SET); char ch = fgetc(pf); printf("%c\n", ch); fclose(pf); pf = NULL; return 0; }
Before running the code, we input a string in the corresponding folder in advance (the following codes are like this):
Code: fseek(pf, 2, SEEK_SET);
Is it right to seek_ Are you confused? Don't worry, look down.
3 functions for locating file pointer offset
SEEK_CUR: the file pointer points to the current location
SEEK_END: the position of the file pointer at the end of the file
SEEK_SET: the file pointer points to the beginning of the file
Code: fseek(pf, 2, SEEK_SET);
Next, we analyze that "abcdef" is put in the original test.txt file.
SEEK_SET: indicates starting from the starting position a. (source location)
2: The offset from the source position is 2.
pf: file pointer
After each reading, the file pointer will be offset backward by 1 by default.
The result we can easily get should be 'c', and the operation results are as follows:
Another Chestnut:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "rb"); if (pf == NULL) { printf("fopen fail\n"); exit(-1); } fseek(pf, -5, SEEK_END); char ch = fgetc(pf); printf("%c\n", ch); fclose(pf); pf = NULL; return 0; }
Operation results:
If SEEK_END is positioned forward from the end of the file, and the offset of the last character is - 1 , And seek_ The situation is different when set is positioned to the beginning. At that time, the default offset of the beginning character is 0.
ftell
Returns the offset of the file pointer from the starting position.
usage method:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "rb"); if (pf == NULL) { printf("fopen fail\n"); exit(-1); } fseek(pf, -3, SEEK_END); char ch = fgetc(pf); printf("%c\n", ch); int ret = ftell(pf); printf("%d\n", ret); fclose(pf); pf = NULL; return 0; }
long ftell( FILE *stream );
FILE *stream: file pointer.
Analysis code:
first, fseek(pf, -3, SEEK_END); Read the position of character D and print character d with an offset of 3.
Each time the character d is read, the file pointer will automatically shift backward by one position. At this time, it refers to the position of the character e, and the offset is 4
Operation results:
rewind
Returns the position of the file pointer to the starting position of the file
Use case:
#include<stdio.h> #include<stdlib.h> int main() { FILE* pf = fopen("test.txt", "rb"); if (pf == NULL) { printf("fopen fail\n"); exit(-1); } fseek(pf, -3, SEEK_END); rewind(pf); char ch = fgetc(pf); printf("%c\n", ch); fclose(pf); pf = NULL; return 0; }
After rewind, the character pointer should point to the beginning, that is, the character 'a'.
Operation results:
File end judgment
feof
Remember: in the process of file reading, the return value of the 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. Check whether the reading of the text file is finished and 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. 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 returned value is less than the actual number to be read. / / \ n it is also a read value
Examples of text files
#include <stdio.h> #include <stdlib.h> int main(void) { int c=0; // Note: int, not char, requires EOF processing FILE* fp = fopen("test.txt", "r"); if (!fp) //If fp is NULL,! If p is true, enter the if statement { 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("\nI/O error when reading"); else if (feof(fp)) puts("\nEnd of file reached successfully"); fclose(fp); fp = NULL; }
Examples of binary files
#include<stdio.h> enum { SIZE = 5 }; int main() { double a[SIZE] = { 1.0,2.0,3.0,4.0,5.0 }; double b = 0.0; size_t ret_code = 0; FILE* fp = fopen("test.txt", "wb"); // Binary mode must be used fwrite(a, sizeof(*a), SIZE, fp); // Write an array of double fclose(fp); fp = fopen("test.txt", "rb"); // Read array of double while ((ret_code = fread(&b, sizeof(double), 1, fp)) >= 1) { printf("%lf\n", b); } if (feof(fp)) printf("Error reading test.txt: unexpected end of file\n"); else if (ferror(fp)) { perror("Error reading test.txt"); } fclose(fp); fp = NULL; }
Operation results: