C language file operation

Keywords: C

catalogue

What is a file

file name

file type

  file buffer

field name pointer  

  Opening and closing of files

Sequential reading and writing of files

fgetc

fputc

fgets

fputs

fprintf

fscanf

fwrite 

fread

sprintf

 sscanf

Compare a set of functions

Random reading and writing of files

fseek

  3 functions for locating file pointer offset

ftell

rewind

File end judgment  

feof

Examples of text files

Examples of binary files

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:

Posted by thomasd1 on Sat, 02 Oct 2021 14:43:00 -0700