The content to be shared in this chapter is the content of file operations in C language. In order to facilitate your learning, the directory is as follows
Table of contents
4. Sequential reading and writing of files
4.1 Introduction to sequential read and write functions
1. Why use files
When we studied the structure earlier, we wrote the address book program. When the address book is running, we can add and delete data in the address book. At this time, the data is stored in the memory. When the program exits, the address book The data in the address book will naturally disappear, and the data will have to be re-entered when the address book program is run next time. It will be very uncomfortable to use such an address book.
We are thinking that since it is an address book, the information should be recorded. Only when we choose to delete the data, the data will no longer exist.
This involves the problem of data persistence. Our general data persistence methods include storing data in disk files and storing them in databases. Using files, we can store data directly on the hard disk of the computer, achieving data persistence.
2. What is a file
My answer is that files on disk are files.
That is to say, when you turn on your computer, you will see that there are disks C and D on the computer, or some people have bought a hard disk with a larger capacity, and all the things in these hard disks can be converted into files.
But in programming, we generally talk about two kinds of files: program files and data files.
2.1 Program files
Including .c files and .cpp files when we write code, these are called source files. There are also object files (windows environment suffix .obj), executable programs (windows environment suffix .exe), that is, the files generated when we write code and run are called program files
You can simply write a code to show it
Then open the file according to the file path
We can see that C Source is the source file mentioned above
Then enter the Debug folder
You can see the .exe file and .OBJ file we mentioned above, these are program files
2.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.
The address book mentioned above can only be stored in the memory when it is running, and the content will be lost when it is used next time, so it must be stored and then stored as a file on the hard disk so that it can be used whenever you want. Let’s go deep below Research.
Our code will generate an .exe file when compiling, which is the result of adding, deleting, modifying and checking in the address book, so how to put it on the hard disk? Draw a picture here to show everyone
If I want to store the generated program file in the hard disk, that is, store it in a .txt file, the data file is stored in this way.
This article specifically talks about the operation of writing and reading.
Before that, there are some other things to know
2.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 identifier is often called the file name.
How does the file work?
3. File opening and closing
Opening and closing files is like using a refrigerator. To use the items in the folder, you must first use the same as using the refrigerator. Open the refrigerator, then use the contents, and finally close the refrigerator, that is, close the folder. This operation can be read or write, and finally close the folder.
3.1 File Pointer
Seeing the word pointer, some people may think of various pointers such as array pointers and function pointers that they learned before, but in fact, file pointers are different from them. File pointers themselves are pointers of a defined type.
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.
Let's use pictures to understand
The meaning in the figure is that when we want to read or write the data.txt data file, it will actively maintain a piece of memory. This piece of memory is called the file information area. This file information is to describe this piece of data. For the file, it is used to store the information of the file, such as the name of the file, the status of the file, and the current location of the file.
Then how is this file information area stored in memory? Then use FILE to open up a space
Use FILE f to open up this section of file information area, and f can also be understood as a structure variable, and the type of this structure is FILE.
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, so 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, as shown below
3.2 Opening and closing
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.
example
/打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );
Let's go to the official website to see the analysis of the two functions
You can see that there are two parameters, the first parameter means the file name, which is the name of the file you want to operate, and the second parameter is the opening method. What are the ways to open it? Depends on what you do with the file.
Open as shown below
It can be seen that there are many different ways to open
Here is a summary of several
Next, write the code by hand
int main()
{
//打开文件
FILE* pf=fopen("test.txt", "w");
//写文件
//关闭文件
return 0;
}
This is a way to open a file for writing
But what we need to pay attention to is that there is no such file in my file path
Then you need to look at the contents of the table
When there is no file we want to open, he will create a new file, and then we should also pay attention to the return type of the function, which is a pointer type, so we might as well
Define a FILE * type pointer variable pf to receive. At this time, put the address of the file information area we mentioned above into pf, and pf can find the address of the file information area, and then you can find the file and operate the file. The above is to open the file operation
We can see that there will be errors in the above operation corresponding table. If the file fails to open, a null pointer will be returned, so we need to judge its return value as before.
The following code is the normal and complete operation code for opening a file
int main()
{
//打开文件
FILE* pf=fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件
return 0;
}
Next is how to close the file
We can see that the return type is an integer, and the parameter only needs to pass the file pointer to it
At the same time, after we close the file, we need to avoid the use of wild pointers, so we should also turn them into null pointers.
At this time the code runs
We'll find the file we created in the folder
It is the test.c file with a size of 0kb.
Then we change the form of writing to open in the form of reading? There is an error on the form
the code runs
You can see that when you change w to r, you can see that there is an error opening the file.
The path we mentioned above to open the test.c file is a relative path, that is, the path to operate the file in the current project area.
So what if you want to operate other files?
Here I use the files on the desktop to demonstrate
There is a test.c file on the desktop, we want to know its file path, we can right click to open her properties
At this time, we can copy his file path to the parameter of the fopen function
int main()
{
//打开文件
FILE* pf=fopen("C:\\Users\\19110\\Desktop\\test2.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
You can see that the opening is successful (because it is empty text, so there is nothing)
When we use the write operation to open it, that is, change r to w , the system will create a new txt file on the desktop, and you can try it out.
The above is the operation of opening and closing files.
4. Sequential reading and writing of files
4.1 Introduction to sequential read and write functions
Next, share some read and write functions
We can see that each function has different objects, some are for characters, some are for text lines, some are for formatting, and some are for binary. We will explain them one by one.
4.1.1 fputc
First about fputc
We can check the information about fputc on the official website
We can see that the return type of this function is integer, the first parameter is the character you want to output, and the second parameter is the file pointer, directly upload the code for everyone to use briefly
int main()
{
//打开文件
FILE* pf=fopen("C:\\Users\\19110\\Desktop\\test2.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fputc('a', pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
It can be seen that we use fputc in the module for writing files, the a in the brackets is the character we want to output, and pf is the file pointer we want to operate
the code runs
It can be seen that it has run successfully
Then open the file in our fopen to see if a is written into the test file
We can see that a is already in the test file.
If we want to enter a string, such as twenty-six should be letters, we might as well use the while loop
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//把二十六个英文字母写入
int i = 0;
for (i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
Let the code go
You can see that the English letters we wrote already exist in the test file.
Note (the essence of the character is the ASCII code value, so a can be added to i).
4.1.2 fgetc
Next is the read file operation
You can observe the official description of fgetc
It can be seen that the return type of the function is int type, and the parameter of the function is a file pointer;
The official description below is about the return value being int type: if an error occurs when reading, EOF will be returned, and the value of EOF is -1, so not only will it return the ASCII code value, but it may also return -1 , so the return type is defined as int type;
Or the above code we transform it
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ch = fgetc(pf);
printf("%c\n", ch);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
We change 'w' to 'r' to operate the file by reading. This file contains the 26 English letters we wrote.
Let the code go
There may be doubts here, why is the output not aaaaaaaaa...?
This is a special effect of fgetc, every time it reads a character it will move to the next one, I hope everyone can understand.
4.1.3 fputs
According to the usual practice, first observe the information on the official website
The function has two parameters, the first parameter is a string, the second parameter is a file, and the return type is an integer type of data
Use the code to simply understand his use
int main()
{
//读文件
FILE* pf = fopen("text", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写数据
fputs("hello world",pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
The code runs and observes
We see that the write has been successful
What if we write one more time below?
operation result
When we open this file again to check whether they have been written, you will find that they appear on the same line. It is very simple to want them to appear on two lines, just add \n at the end
should not be difficult to understand
4.1.4 fgets
Still first observe the official description
You can see that the return type of the function is the pointer type of char*, and there are three parameters. The content of his parameters is also introduced below
The first parameter means to copy the string of the file in the third parameter to the first parameter;
The second parameter means how many characters to copy at most to the first parameter (note that '\0' is also a character, so write one more number than the string you want to copy);
The third parameter is the file to be operated on
Continue to use the code simply, or operate on the file we just created;
int main()
{
//打开文件
FILE* pf = fopen("text", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读数据
char arr[20];
fgets(arr, 5, pf);
printf("%s\n", arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
operation result
You can see that you want to copy 5 characters in the function, but there are only four characters in the output result. This function puts '\0' at the end
should not be difficult to understand
4.1.5 fprintf
First observe the official description of it
fprintf first
Some people may be confused when seeing this parameter, so we might as well compare the printf we have learned
You will find that the parameter is just one more file pointer
Then when using it, we only need to add one more parameter to printf
Below is the simple code to use
struct S
{
int n;
float f;
char arr[20];
};
int main()
{
struct S s = {100,3.14f,"zhangsan"};
//打开文件
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fprintf(pf,"%d %f %s", s.n, s.f, s.arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
run up
We will find that it has been written in the corresponding file
4.1.6 fscanf
Compare it to the scanf we have learned first
It can be seen that there is still only one more function to operate the file.
Then we use code to make it simple and practical
struct S
{
int n;
float f;
char arr[20];
};
int main()
{
struct S s = { 0 };
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fscanf(pf,"%d %f %s", &(s.n), &(s.f), s.arr);
printf("%d %f %s", s.n, s.f, s.arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
It can be seen that we initialize the content of the structure to 0 at the very beginning, because we need to use the function to read the content of the file itself, which is the file we wrote with fprintf above.
After we read successfully, we will print out the content we read
Let the code run
You can see that all the information in this file has been read out.
The above is what I want to share this time. If it is helpful to you, you may wish to support it three times. Thank you for reading.