C language - file operation

foreword

After writing the address book program, when the address book is running, you can add or delete data in the address book. At this time, the data is stored in the memory. When the program exits, the data in the address book will naturally disappear. It exists, and when the address book program is run next time, the data has to be re-entered. It is very uncomfortable to use such an address book.

Since it is an address book, the information should be recorded. Only when you choose to delete the data, the data will no longer exist. This involves the problem of data persistence. Generally, the methods of data persistence include storing data in disk files and storing them in databases.

Using files can store data directly on the hard disk of the computer, achieving data persistence.

what is a file

document:

Files on disk are files.

However, in program design, there are generally two types of files: program files and data files (classified from the perspective of file functions).

When the program reads and writes the file, it may read data from the file and put it into the program or write the data in the program to the file—data file

program files:

Including source program file (suffix .c), object file (windows environment suffix .obj), executable program (windows environment suffix .exe).

Note: The object file is a temporary file generated during program compilation

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 the file from which the program needs to read data, or the file that outputs the content.

Note:

  • The input and output of the data processed before are all targeted at the terminal, that is, the data is input from the keyboard of the terminal, and the running results are displayed on the monitor.
  • In fact, sometimes the information is output to the disk, and when needed, the data is read from the disk to the memory for use. What is processed here is the file on the disk.

file name:

A file must have a unique file identifier for user identification and reference.

The file name consists of three parts: file path + file name trunk + file suffix (for example: c:\code\test.txt)

Note: For convenience, the file ID is often referred to as the file name.

file opening and closing

file pointer

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.

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 of the FILE structure according to the situation of the file, and fill in the information, and 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.

Note: When operating a file, you only need to pay attention to the file information area. When a file is opened, a file information area (used to record the corresponding changes in the file) will be associated with the file. This is what is returned or used when the file is operated. The address of the file information area.

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 .

insert image description here

file opening and closing

Files should be opened before reading and writing, and should be closed after use.

ANSIC stipulates that the fopen function is used to open the file, and the fclose function is used to close the file

fopen

Introduction to the fopen function:

//打开文件
FILE * fopen ( const char * filename, const char * mode );

fopen is used to open files

Note:

  • The meaning of the return value of the fopen function is that when the file is opened with the fopen function, it will actively create a file information area and return the starting address of the file information area.
  • 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.
  • Returns NULL when the fopen function encounters an error
  • When opening a file, the file name part can be written as an absolute path (care should be taken to prevent \ from being interpreted as an escape sequence character) or as a relative path

Open as follows:

file usage meaning If the specified file does not exist
"r" (read-only) To enter data, open an existing text file go wrong
"w" (write only) To output data, open a text file create a new file
“a” (append) Add data to the end of the text file create a new file
"rb" (read-only) To enter data, open a binary file go wrong
"wb" (write only) To output data, open a binary file create a new file
“ab” (append) append data to the end of a binary file go wrong
"r+" (read and write) Open a text file for reading and writing go wrong
"w+" (read and write) For reading and writing, suggest a new file create a new file
"a+" (read and write) Open a file for reading and writing at the end of the file create a new file
"rb+" (read and write) Open a binary file for reading and writing go wrong
"wb+" (read and write) Create a new binary file for reading and writing create a new file
"ab+" (read and write) Open a binary file for reading and writing at the end of the file create a new file

Use of the fopen function:

Example one:

#include <stdio.h>

int main()
{
    
    
	FILE* pf = fopen("test.dat", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

Example two:

#include <stdio.h>


int main()
{
    
    
	FILE* pf = fopen("C:\\lc\\C语言(新)\\文件操作(一)\\文件操作(一)\\test.dat", "w");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

fclose

Introduction to the fclose function:

//关闭文件
int fclose ( FILE * stream );

fclose is used to close the file

Note: Failure to free memory will result in a memory leak. The number of files that can be opened by a process or a program is limited. Opening a file is a kind of resource. If you only open it but not release it at this time, you will not be able to open the file later.

Use of the fclose function:

Example one:

#include <stdio.h>

int main()
{
    
    
	FILE* pf = fopen("test.dat", "w");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

Sequential reading and writing of files

Function Function name apply to
Character input function (read a character from a file) fgetc all input streams
Character output function (write a character to a file) fputc all output streams
text line input function fgets all input streams
text line output function fputs all output streams
format input function fscanf all input streams
format output function fprintf all output streams
binary input fread document
binary output fwrite document

Replenish:

  • Input (read) is to read the data in the file in the hard disk to the program in the memory
  • Output (write) is the data of the program in memory and put it on the hard disk (or write it to a file)

fputc

Introduction to the fputc function:

int fputc ( int character, FILE * stream );

fputc is used to write a character to a stream (a stream such as a file) or to standard output

Use of the fputc function:

Example one:

insert image description here

Example two:

insert image description here

Replenish:

  • Stream is a highly abstract concept. The reading and writing methods of hardware are different. For programmers to write programs to operate various hardware, they should understand the reading and writing methods of various hardware, but the cost is too high , the requirements for programmers are too high. To write to different devices, you need to know the read and write forms of different devices. At this time, a layer is abstracted between the program and the hardware—stream. The program inputs data into the stream, and the stream then transfers The corresponding data is written to different devices. As for how to read and write data to these external devices, the stream is concerned, and the programmer does not need to care about writing the program and only needs to put the data in the stream.
  • When you open a file and write a file, you can actually understand the file as a stream and write data to the file stream.
  • As long as the C language program is running, three streams are opened by default: stdin (standard input stream-keyboard), stdout (standard output stream-screen), stderr (standard error stream-screen). The types of these three streams are all FILE* types

fgetc

Introduction to the fgetc function:

int fgetc ( FILE * stream );

fgetc is used to read a character from a stream (a stream such as a file) or into standard input

Note:

  • If the fgetc function reads normally, it will return the ASCII value of the character as an integer. If the read fails or encounters a file failure, it will return EOF (-1)
  • The return type of the fgetc function is an int type. The reason is: the read is a character, and the ASCII value of the character is an integer; when the read fails, it may return EOF (the essence of EOF is -1), and the char type variable is to store the ASCII value of the character. Yes, it has no way to store an integer like -1. An integer needs 32 bits and a char needs 8 bits. It can’t be stored. At this time, it is most appropriate to use an integer to receive (use int to receive char More than enough, char receives int is not acceptable).

Use of fgetc function:

Example one:

//使用fgetc从文件流中读取数据
int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	int ret = fgetc(pf);
	printf("%c\n", ret);  //a
    ret = fgetc(pf);
	printf("%c\n", ret);  //b
	ret = fgetc(pf);
	printf("%c\n", ret);  //c
	
	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

Example two:

insert image description here
Example three:

insert image description here

fputs

Introduction to the fputs function:

int fputs ( const char * str, FILE * stream );

fputs is used to write a string to a stream

Use of the fputs function:

Example one:

insert image description here
insert image description here

fgets

Introduction to the fgets function:

char * fgets ( char * str, int num, FILE * stream );

fgets is used to read a string from a stream

Note:

  • The parameter num in the fgets function indicates the maximum number of characters to read (how many characters can be read at most)
  • The fgets function assumes that the parameter passed by the parameter is num characters. In fact, it will read num-1 characters when it is actually read, because a \0 position will be left in this space at the end.

Use of the fgets function:

Example one:

insert image description here

fprintf

Introduction to the fprintf function:

int fprintf ( FILE * stream, const char * format, ... );

The fprintf function is used to write formatted data to a stream

Use of fprintf function:

Example one:

insert image description here

fscanf

Introduction to the fscanf function:

int fscanf ( FILE * stream, const char * format, ... );

The fscanf function is used to read formatted data from a stream

Use of fscanf function:

Example one:

struct S
{
    
    
	char arr[10];
	int num;
	float sc;
};

int main()
{
    
    
	struct S s = {
    
    0};
	//对格式化的数据进行写文件
	FILE* pf = fopen("test.txt", "r");
	if (NULL == pf)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	fscanf(pf, "%s %d %f", s.arr, &(s.num), &(s.sc));

	//打印
	fprintf(stdout, "%s %d %f\n", s.arr, s.num, s.sc);  //abcdef 10 5.500000

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

fwrite

Introduction to the fwrite function:

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

The fwrite function is used to write data to the stream

Use of the fwrite function:

Example one:

insert image description here

Note:

  • The content of the string written in binary form is the same as that written in text form.
  • A text editor opens a file as text to view its contents

fread

Introduction to the fread function:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

The fread function is used to read data from a stream

Note:

  • The fwrite function writes count size data in ptr to the stream, and the fread function reads count size data from the stream into the space pointed to by ptr.
  • The fread function returns the number of complete elements actually read (actually read data). If the return value of the fread function is less than the actual number of counts to be read, it means that the fread has been read this time and it is impossible to read the data again. Don't read it again after reading it this time.

Use of the fread function:

Example one:

//fread读取
struct S
{
    
    
	char arr[10];
	int num;
	float sc;
};

int main()
{
    
    
	struct S s = {
    
    0};
	//二进制的形式读
	FILE*pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	fread(&s, sizeof(struct S), 1, pf);

	printf("%s %d %f\n", s.arr, s.num, s.sc);//abcde 10 5.500000

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

classic interview questions

Compare a set of functions:

scanf/fscanf/sscanf

printf/fprintf/sprintf

sscanf

Introduction to sscanf function:

int sscanf ( const char * s, const char * format, ...);

The sscanf function is used to read formatted data from a string

Use of sscanf function:

Example one:

#include <stdio.h>

struct S
{
    
    
	char arr[10];
	int age;
	float f;
};

int main()
{
    
    
	struct S s = {
    
     "hello", 20, 5.5f };
	struct S tmp = {
    
     0 };

	char buf[100] = {
    
    0};
	//sprintf 把一个格式化的数据,转换成字符串
	sprintf(buf, "%s %d %f", s.arr, s.age, s.f);
	printf("%s\n", buf);  //hello 20 5.500000

	//从buf字符串中还原出一个结构体数据
	sscanf(buf, "%s %d %f", tmp.arr, &(tmp.age), &(tmp.f));
	printf("%s %d %f\n", tmp.arr, tmp.age, tmp.f);  //hello 20 5.500000

	return 0;
}

sprintf

Introduction to the sprintf function:

int sprintf ( char * str, const char * format, ... );

The sprintf function is used to write formatted data to a string

Use of the sprintf function:

Example one:

#include <stdio.h>

struct S
{
    
    
	char arr[10];
	int age;
	float f;
};

int main()
{
    
    
	struct S s = {
    
     "hello", 20, 5.5f };
	struct S tmp = {
    
     0 };

	char buf[100] = {
    
    0};
	//sprintf 把一个格式化的数据,转换成字符串
	sprintf(buf, "%s %d %f", s.arr, s.age, s.f);
	printf("%s\n", buf);  //hello 20 5.500000

	//从buf字符串中还原出一个结构体数据
	sscanf(buf, "%s %d %f", tmp.arr, &(tmp.age), &(tmp.f));
	printf("%s %d %f\n", tmp.arr, tmp.age, tmp.f);  //hello 20 5.500000

	return 0;
}

Summarize:

  • The scanf function is a formatted input statement to the standard input - stdin
  • The fscanf function is a formatted input statement for all input streams - stdin, file
  • The sscanf function reads a formatted data from a string (converts a string into formatted data)
  • The printf function is a formatted output statement to standard output - stdout
  • The fprintf function is a formatted output statement for all output streams - stdout, file
  • The sprintf function writes formatted data into a string (converts a formatted data into a string)

Random reading and writing of files

fseek

Introduction to the fseek function:

The function of the fseek function is to locate the file pointer according to the position and offset of the file pointer.

int fseek ( FILE * stream, long int offset, int origin );

Note:

  • origin indicates the starting position, and there are three options for the starting position value: SEEK_SET (the starting position of the file), SEEK_CUR (the position of the current file pointer), and SEEK_END (the end of the file)
  • The unit of fseek function offset is byte

Use of fseek function:

Example one:

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读取文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	//调整文件指针
	fseek(pf, -2, SEEK_CUR);

	ch = fgetc(pf); //-1
	printf("%c\n", ch);//空格
	ch = fgetc(pf); //-1
	printf("%c\n", ch);//空格



	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

Example two:

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读取文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	//调整文件指针
	fseek(pf, -1, SEEK_CUR);

	ch = fgetc(pf);
	printf("%c\n", ch);//a
	ch = fgetc(pf);
	printf("%c\n", ch);//b



	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

Example three:

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读取文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	//调整文件指针
	fseek(pf, 2, SEEK_CUR);

	ch = fgetc(pf);
	printf("%c\n", ch);//d
	ch = fgetc(pf);
	printf("%c\n", ch);//e



	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

Example four:

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读取文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	//调整文件指针
	fseek(pf, 2, SEEK_END);

	ch = fgetc(pf);
	printf("%c\n", ch);//空格
	ch = fgetc(pf);
	printf("%c\n", ch);//空格

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

ftell

Introduction to the ftell function:

The ftell function returns the offset of the file pointer relative to the starting position.

long int ftell ( FILE * stream );

Use of the ftell function:

Example one:

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读取文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	//调整文件指针
	fseek(pf, -2, SEEK_END);

	ch = fgetc(pf);
	printf("%c\n", ch);//e
	ch = fgetc(pf);
	printf("%c\n", ch);//f

	int ret = ftell(pf);
	printf("%d\n", ret);//6

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

rewind

Introduction to the rewind function:

The function of the rewind function is to return the position of the file pointer to the beginning of the file.

void rewind ( FILE * stream );

Use of the rewind function:

Example one:

int main()
{
    
    
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读取文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	//调整文件指针
	fseek(pf, -2, SEEK_END);

	ch = fgetc(pf);
	printf("%c\n", ch);//e
	ch = fgetc(pf);
	printf("%c\n", ch);//f

	int ret = ftell(pf);
	printf("%d\n", ret);

	//让文件指针回到起始位置
	rewind(pf);
	ch = fgetc(pf);
	printf("%c\n", ch);//a

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

text files and binary files

Depending on how the data is organized, data files are called text files or binary files.

Data is stored in binary form in memory, and if it is output to external storage without conversion, it is a binary file. If it is required to store in the form of ASCII code on the external storage, it needs to be converted before storage. A file stored in the form of ASCII characters is a text file.

Characters are all stored in ASCII form, and numeric data can be stored in either ASCII or binary form.

Example one:

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), and it will only occupy 4 bytes on the disk if it is output in binary form.

int main()
{
    
    
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件
	fwrite(&a, sizeof(int), 1, pf);

	fclose(pf);
	pf = NULL;
	return 0;
}

insert image description here
insert image description here

Judgment of the end of file reading

Note: During the file reading process, the return value of the feof function cannot be used to directly determine whether the file is over. The feof function is used when the file reading ends, to judge whether the reading fails to end, or the end of the file is encountered (the function of the feof function is what causes the reading to end after the reading has ended).

  1. Whether the reading of the text file is over, judge whether the return value is EOF ( fgetc ), or NULL (fgets)
  • The fgetc function returns EOF at the end of reading. When reading normally, what is returned is the ASClI code value of the character read.
  • The fgets function returns NULL at the end of the read. When reading normally, return the starting address of the space where the character string is stored.
  1. Judging the end of reading the binary file, and judging whether the return value is less than the actual number to be read.
  • When the fread function reads, it returns the number of complete elements actually read. If it is found that the number of complete elements read is less than the specified number of elements, this is the last read.

Example one:

//写代码把test.txt文件拷贝一份,生成test2.txt

int main()
{
    
    
	FILE* pfread = fopen("test.txt", "r");
	if (pfread == NULL)
	{
    
    
		return 1;
	}
	FILE* pfwrite = fopen("test2.txt", "w");
	if (pfwrite == NULL)
	{
    
    
		fclose(pfread);
		pfread = NULL;
		return 1;
	}
	//文件打开成功
	//读写文件
	int ch = 0;
	while ((ch = fgetc(pfread)) != EOF)
	{
    
    
		//写文件
		fputc(ch, pfwrite);
	}
	
	if (feof(pfread))   //如果遇到文件结束会返回非0,如果遇到文件末尾EOF而结束的会返回非0
	{
    
    
		printf("遇到文件结束标志,文件正常结束\n");
	}
	else if(ferror(pfread))  //如果ferror(pfread)返回的是非0表示是因为文件读取失败而停止的
	{
    
    
		printf("文件读取失败结束\n");
	}

	//关闭文件
	fclose(pfread);
	pfread = NULL;
	fclose(pfwrite);
	pfwrite = NULL;

	return 0;
}

file buffer

The ANSIC standard uses the "buffer file system" to process data files. The so-called buffer file system means that the system automatically creates a "file buffer" in the memory for each file being used in the program. 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 data is read from the disk to the computer, the data read from the disk file is input to the memory buffer (full of the buffer), 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.

insert image description here
When writing a program, various variables will be created in the program. These variables must apply for space in the memory. After the space is allocated, data will be stored in it. It is assumed that the data comes from the hard disk or read files. The data read from the hard disk should not be directly put into the program data area (variables), but firstly put into the input buffer, and then put into the program data area after the input buffer is full. If you want to put some data on the hard disk or store it in a file later, put the data in the output buffer first, and then put it on the hard disk after the output buffer is full.

When there is data in the program to be written to the hard disk (file), note that writing data does not mean that you can write it as you want. At this time, the data must be written to the hard disk, and the operating system must write the data to the hard disk. When you want to write to the hard disk through the operating system, you should pay attention to whether the operating system should be interrupted when the operating system is writing (the OS may do this at this time, and the OS needs to stop to help write data at this time), if the operating system If you are frequently interrupted like this, the OS will not do anything. At this time, a buffer is needed, fill the buffer with data, and then write the data in the buffer to the hard disk at one time. In this way, the efficiency of the operating system will be found to be improved.

Test for buffer existence:

#include <stdio.h>
#include <windows.h>
//VS2013 VS2019 WIN10环境测试
int main()
{
    
    
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//先将代码放在输出缓冲区

	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);  //睡10秒
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)

	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);

	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;

	return 0;
}

Note:

  • The above code may not be tested under some compilers
  • If the data in the buffer is not written directly when the file is closed, the information in the buffer will be written directly to the hard disk when the file is closed

Summary: Because of the existence of the buffer, when the C language operates the file, it needs to refresh the buffer or close the file at the end of the file operation. Failure to do so can cause problems reading and writing files.

Guess you like

Origin blog.csdn.net/AI_ELF/article/details/121502270