C language file operation
1. What is a file?
Files on disk are files.
Computer files are a type of file. Different from ordinary file carriers, computer files are a collection of information stored on a computer using the computer hard disk as a carrier.
*Why use files
Using files, we can store data directly on the computer's hard drive, achieving data persistence.
——But in programming, we generally talk about two types of files: program files and data files:
program files
Including source program files (suffix .c), target 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 is running, such as a file that needs to read data from when the program is running, or a file that outputs content.
2. File name
A file must have a unique file identifier so that users can identify and reference it.
The file name contains 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.
3. File type
Depending on how the data is organized, data files are called text files or binary files .
The data is stored in binary form in the memory. If it is output to external memory without conversion, it is a binary file .
If it is required to be stored in ASCII code in external storage, it needs to be converted before storage. Files stored in the form of ASCII characters are text files .
How is data stored in memory?
Characters are always stored in ASCII form, and numerical data can be stored in either ASCII or binary form.
For example, if there is an integer 10000, if it is output to the disk in the form of ASCII code, it will occupy 5 bytes on the disk (one byte for each character), while if it is output in binary form, it will only occupy
4 bytes on the disk.
Code test: (If you don’t understand here, you can read below to understand the file pointer)
#include <stdio.h>
int main()
{
int a = 10000;
FILE* pf = fopen("test.txt", "wb");
fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
fclose(pf);
pf = NULL;
return 0;
}
Running result: (binary garbled code)
can be interpreted using the method I found from the data:
Result display:
4. File buffer
The ANSIC standard uses a "buffer file system" to process data files. The so-called buffer file system means that the system automatically creates a "file buffer" in memory for each file being used in the program.
The data output from the memory to the disk will be sent to the buffer in the memory first, and then sent to the disk together after the buffer is filled.
If data is read from the disk to the computer, the data is read from the disk file and input into the memory buffer (the buffer is filled), and then the data is sent 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.
Code example:
#include <stdio.h>
#include <windows.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf);//先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
//注:fflush 在高版本的VS上不能使用了
printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭文件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}
Here we must focus on understanding the role of fflush;
when it first starts running for 10 seconds, there is no data in the opened file:
after waiting for the program to run for 10 seconds, you will get:
5. File pointer (key points)
In the buffered file system, the key concept is the "file type pointer", referred to as the "file pointer".
Each used file opens up a corresponding file information area in the memory to store file-related information (such as file name, file status and 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 VS2013 compilation environment has the following file type declaration:
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
}; typedef struct _iobuf FILE;
The contents of the FILE type of different C compilers are not exactly the same, but they are similar.
Whenever a file is opened, the system will automatically create a variable in the FILE structure based on the file's condition and fill in the information in it. The user does not need to care about the details
.
Generally, the variables of this FILE structure are maintained through a FILE pointer, which makes it more convenient to use.
Below we can create a pointer variable of FILE*:
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. In other words, the file associated
with it can be found through the file pointer variable . for example:
Opening and closing files
The file should be opened before reading or writing, and the file should be closed after use.
When writing a program, when a file is opened, a FILE* pointer variable pointing to the file will be returned, which is equivalent to establishing a relationship between the pointer and the file.
ANSIC stipulates that the 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 );
Open as follows:
Code example:
/* fopen fclose example */
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ("myfile.txt","w");
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
fclose (pFile);
}
return 0;
}
There are two ways to open the address of a file:
relative path
For example:
pFile = fopen ("myfile.txt","w");
pFile = fopen (".\\myfile.txt","w");//当前目录
pFile = fopen ("..\\myfile.txt","w");//上一级目录
absolute path
For example:
pFile = fopen ("C:nser\\Admin\\desktop\\myfile.txt","w");
Sequential reading and writing of files (difficulty)
Get characters from stream
Write characters to stream
Get string from stream
Write string to stream
Code example:
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
int i = 0;
for (i = 0; i < 26; i++)
{
fputc('a'+i, stdout);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
Here fputc will store the data in the text file data.txt. Legend:
There is also a simple application of fgetc:
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ch = fgetc(stdin);
printf("%c\n", ch);
ch = fgetc(stdin);
printf("%c\n", ch);
ch = fgetc(stdin);
printf("%c\n", ch);
ch = fgetc(stdin);
printf("%c\n", ch);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fgetc will read characters from the previous data.txt text file, and after each reading, fgetc will point to the next character and read it in sequence, such as the following figure:
fputs code example:
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//写文件 - 写一行
fputs("hello bit\n", pf);
fputs("hello xiaobite\n", pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fputs will print the two read strings on the same line.
Change the content in data.txt to:
fgets will read a string of specified size from the second, code example:
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//读文件 - 读一行
char arr[10] = {
0 };
fgets(arr, 10, pf);
printf("%s", arr);
fgets(arr, 10, pf);
printf("%s", arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
Code running results:
Compare a set of functions:
scanf/fscanf/sscanf
Read formatted data from stdin
Read formatted data from stream
Read formatted data from string
printf/fprintf/sprintf
Print formatted data to standard output
Write formatted data to stream
Write formatted data to a string
fprintf code example:
#include<stdio.h>
struct S
{
int a;
float s;
};
int main()
{
FILE* pf = fopen("data.txt", "w");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//写文件
struct S s = {
100, 3.14f };
fprintf(pf, "%d %f", s.a, s.s);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
Code running results:
fscanf code example:
#include<stdio.h>
struct S
{
int a;
float s;
};
int main()
{
FILE* pf = fopen("data.txt", "r");
if (NULL == pf)
{
perror("fopen");
return 1;
}
//写文件
struct S s = {
0};
fscanf(pf, "%d %f", &(s.a), &(s.s));
fprintf(stdout, "%d %f", s.a, s.s);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
sprintf code example:
#include<stdio.h>
struct S
{
int a;
float s;
char str[10];
};
int main()
{
char arr[30] = {
0 };
struct S s = {
100, 3.14f, "hehe" };
sprintf(arr, "%d %f %s", s.a, s.s, s.str);
printf("%s\n", arr);
return 0;
}
Running results:
sscanf code example:
#include<stdio.h>
struct S
{
int a;
float s;
char str[10];
};
int main()
{
char arr[30] = {
0 };
struct S s = {
100, 3.14f, "hehe" };
struct S tmp = {
0};
sprintf(arr, "%d %f %s", s.a, s.s, s.str);
sscanf(arr, "%d %f %s", &(tmp.a), &(tmp.s), tmp.str);
printf("%d %f %s\n", tmp.a, tmp.s, tmp.str);
return 0;
//}
Code running result:
write data block to stream
Read chunks of data from the stream
fwrite code demonstration:
#include<stdio.h>
struct S
{
int a;
float s;
char str[10];
};
int main()
{
struct S s = {
99, 6.18f, "bit" };
FILE* pf = fopen("data.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fwrite(&s, sizeof(struct S), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
Code running result:
This is a binary result, so the display is garbled; however, fread can be called to read
the code demonstration:
#include<stdio.h>
struct S
{
int a;
float s;
char str[10];
};
int main()
{
struct S s = {
0 };
FILE* pf = fopen("data.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fread(&s, sizeof(struct S), 1, pf);
printf("%d %f %s\n", s.a, s.s, s.str);
fclose(pf);
pf = NULL;
return 0;
}
operation result:
Random reading and writing of files
fseek
locates the file pointer based on its position and offset.
Reposition the stream position indicator
example:
First change the data in data.txt as shown below:
/* fseek example */
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//定位文件指针到f
fseek(pf, 5, SEEK_SET);//从起始位置开始
int ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
Code running results:
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//定位文件指针到f
fseek(pf, -4, SEEK_END);//从末尾位置开始
int ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
operation result:
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//定位文件指针到f
int ch = fgetc(pf);
printf("%c\n", ch);//a
ch = fgetc(pf);
printf("%c\n", ch);//b
ch = fgetc(pf);
printf("%c\n", ch);//c
fseek(pf, 2, SEEK_CUR);
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
Running result:
Get the current position in the stream, (calculate offset)
Code example:
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//定位文件指针到f
int ch = fgetc(pf);
printf("%c\n", ch);//a
ch = fgetc(pf);
printf("%c\n", ch);//b
ch = fgetc(pf);
printf("%c\n", ch);//c
int pos = ftell(pf);
printf("%d\n", pos);
fclose(pf);
pf = NULL;
return 0;
}
operation result:
Set the position of the stream to the beginning (return to the starting position)
Code demo:
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//定位文件指针到f
int ch = fgetc(pf);
printf("%c\n", ch);//a
ch = fgetc(pf);
printf("%c\n", ch);//b
ch = fgetc(pf);
printf("%c\n", ch);//c
rewind(pf);
ch = fgetc(pf);
printf("%c\n", ch);//a
fclose(pf);
pf = NULL;
return 0;
}
operation result:
6. Determination of file end
incorrectly used feof
Remember: During the file reading process, the return value of the feof function cannot be used directly to determine whether the file is ended.
Instead, it is used when the file reading ends to determine whether the reading failed or the end of the file was encountered .
- Whether the text file reading is completed, determine 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.- The reading end judgment of the binary file determines 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.
Correct use:
Text file example
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int c; // 注意:int,非char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if(!fp) {
perror("File opening failed");
return EXIT_FAILURE;
}
//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))
puts("I/O error when reading");
else if (feof(fp))
puts("End of file reached successfully");
fclose(fp);
}
Binary file example
#include <stdio.h>
enum {
SIZE = 5 };
int main(void)
{
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.bin", "wb"); // 必须用二进制模式
fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
fclose(fp);
fp = fopen("test.bin","rb");
// 读 double 的数组
while((ret_code = fread(&b, sizeof(double), 1, fp))>=1)
{
printf("%lf\n",b);
}
if (feof(fp))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {
perror("Error reading test.bin");
}
fclose(fp);
fp = NULL;
}
Here I will introduce another code for copying files:
//拷贝文件
//拷贝data1.txt 文件,产生一个新的文件data2.txt
#include<stdio.h>
int main()
{
FILE* pfRead = fopen("data1.txt", "r");//打开data1.txt
if (pfRead == NULL)
{
perror("open file for read");
return 1;
}
FILE* pfWrite = fopen("data2.txt", "w");//打开data2.txt
if (pfWrite == NULL)
{
perror("open file for write");
fclose(pfRead);
pfRead = NULL;
return 1;
}
//读写文件
int ch = 0;
while ((ch = fgetc(pfRead)) != EOF)//将data1.txt中的代码依次复制到data2.txt中
{
fputc(ch, pfWrite);
}
//关闭文件
fclose(pfRead);
pfRead = NULL;
fclose(pfWrite);
pfWrite = NULL;
return 0;
}
Summarize
In short, the content of this chapter of file operation is very complicated. I hope you can study it carefully and master it as soon as possible;