C language file operation

C language file operation

1. What is a document

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), header files (suffix. h), 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 runs, such as the file from which the program needs to read data, or the file that outputs the content (such as data.txt).

This discussion is about data files. In the previous chapters, 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

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

2. Opening and closing of files

2.1 file 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 (generate a FILE information area) 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:

2.2 opening and closing of documents

Can the data of the address book also be put in a file and stored on disk - persistent!

The file writes the information in the file. The steps of operating the file are as follows:
1. Open the file
2. Read / write files
3. Close the file

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

fopen (a function provided by c language) ---- > the interface provided by the operating system -------- > system call (file)

The opening method is as follows:

int main()
{
	//Open file
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "w");
                   //On the desktop, you need to write an absolute path
                   //If you are in the same path as the c file, you can directly use "data.txt"
	if (pf == NULL);
	{
		perror("fopen");
		return -1;
	}
	//read file
	//
	//Close file
	fclose(pf);
	pf = NULL;
	return 0;
}

3. Sequential reading and writing of documents

1. Character output function - fputc

//1. Character output function - fputc 
int main()
{
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}

	//Write file
	fputc('b', pf);
	fputc('i', pf);
	fputc('t', pf);

	//Close file
	fclose(pf);
	pf == NULL;
	return 0;
}

stdout - standard output stream

//fputc can also be applied to standard output streams
int main()
{
	fputc('b', stdout);
	fputc('i', stdout);  // Equivalent to putchar
	fputc('t', stdout);
	return 0;
}

2. Character input function - fgetc

//2. Character input function - fgetc  
int main()
{
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return -1;
	}

	//read file
	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

	//Close file
	fclose(pf);
	pf == NULL;
	return 0;
}

The original content in the file is abcdef. The original pointer points to a. read it again, and the pointer automatically points to b,,,

int main()
{
	int ch = fgetc(stdin);    //getchar
	printf("%c\n", ch);       //a

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

	ch = fgetc(stdin);
	printf("%c\n", ch);       //c

		return 0;
}
  1. Text line output function - fputs
//3. Text line output function - fputs
int main()
{
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}
	//Write file
	//Write a line of data
	fputs("hello world\n",pf);
	fputs("hello bit\n", pf);

	//Close file
	fclose(pf);
	pf == NULL;
	return 0;
}

4. Text line input function - fgets

//4. Text line input function - fgets
int main()
{
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}
	//read file
	//Read a row of data
	char arr[20] = { 0 };
	fgets(arr, 20, pf);
	printf("%s\n", arr);

	fgets(arr, 20, pf);   //If you write 5, read 4 characters and put one \ 0 at the end
	printf("%s\n", arr);

	//Close file
	fclose(pf);
	pf == NULL;
	return 0;
}

5. Format input and output

//5. Format input and output
struct S
{
	int n;
	double d;
};
int main()
{
	//struct S s={100,3.14};
	struct S s = { 0};
	//FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "w");
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}

	//Write file
	//fprintf(pf,"%d %lf\n",s.n,s.d);

	//read file
	fscanf(pf, "%d %lf", &(s.n), &(s.d));
	printf("%d %lf\n", s.n, s.d);



	//Close file
	fclose(pf);
	pf == NULL;
	return 0;
}

6. Binary input

//6. Binary input
struct S
{
	int n;
	double d;
	char name[10];
};
int main()
{
	struct S s={100,3.14,"Zhang San"};
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "wb");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}

	//Write file - binary mode
	fwrite(&s, sizeof(s), 1, pf);


	//Close file
	fclose(pf);
	pf == NULL;
	return 0;
}

7. Binary output

//7. Binary output
struct S
{
	int n;
	double d;
	char name[10];
};
int main()
{
	struct S s = { 0 };
	FILE* pf = fopen("C:\\Users\\Administrator\\Desktop\\data.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}

	//Read file - binary mode
	fread(&s, sizeof(s), 1, pf);

	//Print
	printf("%d %lf %s\n", s.n, s.d,s.name);  //100 3.14 sheets 3


	//Close file
	fclose(pf);
	pf == NULL;
	return 0;
}
Compare a set of functions:

scanf reads formatted data from the standard input stream (keyboard)
fscanf reads formatted data from all input streams
sscanf reads a formatted data from a string. / / converts a string into a formatted data

printf prints formatted data to standard output (screen)
fprintf outputs the formatted data to all output streams (screen \ file)
sprintf converts the formatted data into the corresponding string

struct S
{
	int n;
	double d;
	char name[10];
};

int main()
{
	char arr[100] = { 0 };
	struct S s = { 100, 3.14, "Zhang San" };
	struct S tmp = { 0 };
	//Converts a formatted data into a string
	sprintf(arr, "%d %lf %s", s.n, s.d, s.name);

	//Print
	printf("%s\n", arr);

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

//The results are the same twice
//Printed as a string for the first time
//Print the second time in a structured format

4. Random reading of files

fseek

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

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

SEEK_CUR - current position of file pointer
SEEK_SET - initial position
SEEK_END - end position

example:

//File content: abcdef
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	//1. Open the file
	FILE* pf=fopen("data.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}
    
    //2. Reading documents
	//Random reading and writing
	int ch=fgetc(pf);      //After fgetc is executed, the pointer is automatically shifted back by one bit
	printf("%c\n", ch);    //a
    
    //If you want to read c for the first time
	fseek(pf, 2, SEEK_SET);
	 ch=fgetc(pf);
	printf("%c\n", ch);    //c
    
    fseek(pf, -2, SEEK_CUR);
	 ch = fgetc(pf);
	printf("%c\n", ch);    //b
    
    //3. Relevant documents
	fclose(pf);
	pf = NULL;
	return 0;
}

ftell

Returns the offset of the file pointer from the starting position

long int ftell ( FILE * stream );

example:

//File content: abcdef
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	//1. Open the file
	FILE* pf=fopen("data.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}
    
    //2. Reading documents
	//Random reading and writing
	int ch=fgetc(pf);      //After fgetc is executed, the pointer is automatically shifted back by one bit
	printf("%c\n", ch);    //a
    
    //If you want to read c for the first time
	fseek(pf, 2, SEEK_SET);
	 ch=fgetc(pf);
	printf("%c\n", ch);    //c
    
	//Calculates the offset of the file pointer from the starting position
	int ret = ftell(pf);
	printf("%d\n", ret);  //2
    
    //3. Relevant documents
	fclose(pf);
	pf = NULL;
	return 0;
}

rewind

Returns the position of the file pointer to the starting position of the file

void rewind ( FILE * stream );

example:

//File content: abcdef
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	//1. Open the file
	FILE* pf=fopen("data.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return -1;
	}
    
    //2. Reading documents
	//Random reading and writing
	int ch=fgetc(pf);      //After fgetc is executed, the pointer is automatically shifted back by one bit
	printf("%c\n", ch);    //a
    
    //If you want to read c for the first time
	fseek(pf, 2, SEEK_SET);
	 ch=fgetc(pf);
	printf("%c\n", ch);    //c	
    
    //Returns the file pointer to the start of the file
	rewind(pf);
	ch = fgetc(pf);
	printf("%c\n", ch);   //a
    
    //3. Relevant documents
	fclose(pf);
	pf = NULL;
	return 0;
}

5. Text 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 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 (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:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	//1. Read files
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return -1;
	}

	//2. Write files in binary form
	int a = 10000;
	fwrite(&a, 4, 1, pf);

	//3. Close the file
	fclose(pf);
	pf == NULL;
	return 0;
}

6. Judgment of document end

In the process of file reading, the return value of feof function cannot be directly used to judge whether the file is finished. It is used to judge whether the reading fails or the end of the file is encountered when the file reading ends. (that is, feof is used to judge the reason for the end of the file)

  1. Whether the text file reading is completed, 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
  1. Judge whether the return value is less than the actual number to be read after reading the binary file.

For example:

  • fread determines whether the return value is less than the actual number to be read.
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	//1. Open the file
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return -1;
	}


	//2.
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	//If you read the file through fgetc, you can judge whether the return value of fgetc is EOF and whether the file reading is over!
	{
		printf("%c ", ch);
	}

	//3. Close the file
	fclose(pf);
	pf = NULL;
	return 0;
}

The purpose of feof - after reading the file, judge whether it ends when it encounters the end of the file
Purpose of perror - after reading the file, judge whether the reading ends after encountering an error

Text file example:

#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.0,2.0,3.0,4.0,5.0};
    double b = 0.0;
    size_t ret_code = 0;
    FILE *fp = fopen("test.bin", "wb"); // Binary mode must be used
    fwrite(a, sizeof(*a), SIZE, fp); // Write an array of double
    fclose(fp);
    fp = fopen("test.bin","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.bin: unexpected end of file\n");
    else if (ferror(fp)) {
        perror("Error reading test.bin");
   }
    fclose(fp);
    fp = NULL; 
}

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

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Windows.h>
//Vs2013 win10 environment test

int main()
{
	FILE* pf = fopen("test.text", "w");
	fputs("abcdef", pf);
	printf("Sleep for 10 seconds - The data has been written. Open it test.text 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 10 seconds - At this point, open again test.text File, the file has content\n");
	Sleep(10000);
	fclose(pf);
	//Note: fclose also flushes the buffer when closing the file
	pf = NULL;
	return 0;
}

Because of the existence of buffer, c language needs to refresh the buffer or close the file at the end of the file operation.
If not, it may cause problems in reading and writing files.

Tags: C C++ Windows

Posted on Sat, 09 Oct 2021 14:48:54 -0400 by Tjorriemorrie