c language self-study tutorial - file operation

Posted by mrdave on Tue, 22 Feb 2022 14:00:55 +0100

1. Why use files

When we learned the structure earlier, we wrote the program of address book. When the address book runs, we can add and delete data to the address book. At this time, the data is stored in memory. When the program exits, the data in the address book will naturally disappear. The next time we run the address book program, the data will have to be re entered, It's hard to use such an address book.
We are thinking that since it is an address book, we should record the information. Only when we choose to delete the data, the data will no longer exist. This involves the problem of data persistence. Our general methods of data persistence include storing data in disk files, databases and so on.
Using files, we can store the data directly on the hard disk of the computer, so as to achieve the persistence of the data

2. What is a document

Files on disk are files.
But in programming, we generally talk about two kinds of files: program files and data files (classified from the perspective of file function).

2.1 procedure documents

Including source program files (suffix. c), object files (suffix. obj in windows Environment), and executable programs (suffix. exe in windows Environment).

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.

This chapter discusses data files.
In the previous chapters, the input and output of the processed data are targeted at the terminal, that is, input the 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.

2.3 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
For convenience, the file ID is often referred to as the file name.

3. Opening and closing of files

3.1 document pointer

In the buffered file system, the key concept is * * "file type pointer", 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)
Word, file status and current location of the file, etc.). This information is stored in a structure variable. The structure type is systematic
Declared, named FILE
For example, stdio.com provided by VS2013 compilation environment The H header file 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 this 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 pointing to data of type FILE. You can make pf point to the FILE information area of a FILE (which is a structure variable). 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.
such as

3.2 opening and closing of documents

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 stipulates that fopen function is used to open the file and fclose is used to close the file

//Open file
FILE * fopen ( const char * filename, const char * mode );
//Close file
int fclose ( FILE * stream );

The opening method is as follows (note to use double quotation marks)

File usagemeaningIf the specified file does not exist
"r" (read only)To enter data, open an existing text fileerror
"w" (write only)To output data, open a text fileCreate a new file
"a" (added)Add data to the end of a text fileCreate a new file
"rb" (read only)To enter data, open a binary fileerror
"wb only"To output data, open a binary fileCreate a new file
"ab" (additional)Add data to the end of a binary fileerror
"r +" (read / write)To read and write, open a text fileerror
"w +" (read / write)For reading and writing, suggest a new fileCreate a new file
"a +" (read-write)Open a file and read and write at the end of the fileCreate a new file
"rb +" (read and write)Open a binary file for reading and writingerror
"wb +" (read / write)Create a new binary file for reading and writingCreate a new file
"ab +" (read and write)Open a binary file and read and write at the end of the fileCreate a new file

Example code:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
	FILE * pFile;
	//Open file
	pFile = fopen ("myfile.txt","w");
	//File operation
	if (pFile!=NULL)
	{
		fputs ("fopen example",pFile);
		//Close file
		fclose (pFile);
	}
	return 0;
	}

4. Sequential reading and writing of documents

functionFunction nameApply to
Character input functionfgetcAll input streams
Character output functionfputcAll output streams
Text line input functionfgetsAll input streams
Text line output functionfputsAll output streams
Format input functionfscanfAll input streams
Format output functionfprintfAll output streams
Binary inputfreadfile
Binary outputfwritefile

fputc

//Write file
int main()
{
	FILE *pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	char ch = 0;
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		fputc(ch, pf);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

fgetc

//read file
int main()
{
	FILE*pf = fopen("data.txt","r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	int ch = 0 ;//EOF is - 1
	while ((ch = fgetc(pf))!=EOF)
	{
		printf("%c ", ch);
	}

	fclose(pf);
	pf = NULL;

	return 0;
}

fputs

//Write a line
int main()
{
	FILE *pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}

	fputs("hello world\n hehe\n", pf);
	fputs("hehe\n", pf);

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

fgets

//Read a line
int main()
{
	FILE *pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}

	char buf[100] = { 0 };
	fgets(buf, 100, pf);
	printf("%s", buf);
	fgets(buf, 100, pf);
	printf("%s", buf);

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

Comprehensive application

//From data Txt copy into data2 txt
int main()
{
	FILE *pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("open for reading:%s\n", strerror(errno));
		return 0;
	}
	FILE *pw = fopen("data2.txt", "w");
	if (pw == NULL)
	{
		printf("open for wrriting:%s\n", strerror(errno));
		fclose(pf);
		return 0;
	}

	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		fputc(ch, pw);
	}
	fclose(pf);
	fclose(pw);
	pf = NULL;
	pw = NULL;
	return 0;
}

Binary input / output function fwrite, fread Address book items It is useful in the improvement of. Those who are interested can go and have a look

4.1 compare a set of functions:

scanf/fscanf/sscanf
printf/fprintf/sprintf

See the blog for details Comparison of scanf/fscanf/sscanf, printf/fprintf/sprintf functions.

5. Random reading and writing of documents

5.1 fseek

Locate the file pointer according to the position and offset of the file pointer

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

example

/* fseek example */
#include <stdio.h>
int main ()
{
	FILE * pFile;
	pFile = fopen ( "example.txt" , "wb" );
	fputs ( "This is an apple." , pFile );
	fseek ( pFile , 9 , SEEK_SET );
	fputs ( " sam" , pFile );
	fclose ( pFile );
	pFile = NULL;
	return 0;
}

5.2 ftell

Returns the offset of the file pointer from the starting position

long int ftell ( FILE * stream );

example

/* ftell example : getting size of a file */
#include <stdio.h>
int main ()
{
	FILE * pFile;
	long size;
	pFile = fopen ("myfile.txt","rb");
	if (pFile==NULL) perror ("Error opening file");
	else
	{
		fseek (pFile, 0, SEEK_END); // non-portable
		size=ftell (pFile);
		fclose (pFile);
		printf ("Size of myfile.txt: %ld bytes.\n",size);
	}
	return 0;
}

5.3 rewind

Return the position of the file pointer to the starting position of the file

void rewind ( FILE * stream );

example:

/* rewind example */
#include <stdio.h>
int main ()
{
	int n;
	FILE * pFile;
	char buffer [27];
	
	pFile = fopen ("myfile.txt","w+");
	for ( n='A' ; n<='Z' ; n++)
		fputc ( n, pFile);
	rewind (pFile);
	//fseek(pFile, 0, SEEK_SET);
	fread (buffer,1,26,pFile);
	fclose (pFile);
	buffer[26]='\0';
	puts (buffer);
	return 0;
}

6. Text files 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)


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;
}



Because 10000 can be expressed as:

7. Determination of the end of file reading

7.1 frequently 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, and judge 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 return value is less than the actual number to be read.

Examples of using text files correctly:

#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

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 is 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.

File operation is a relatively independent section in c language, but I hope you can gain something.

Topics: C C++