Hand tear C language advanced --- file operation

Keywords: C

catalogue

What is a file

file name

file type

file buffer

field name pointer

Opening and closing of files

fopen and fclose

Sequential reading and writing of files

fputc 

fgetc

fputs 

fgets 

fwrite

fread 

Random reading and writing of files

fseek

ftell

rewind

Document end judgment

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.

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

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

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 VS2008 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 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 following is how to read and write files:  

fopen and fclose

Example code:

/* fopen fclose example */
#include <stdio.h>

int main()
{
	//Open file
	FILE* pf = fopen("data.txt", "r");//Open the file as read-only
	if (pf == NULL)
	{
		perror("fopen ");
		return;
	}
	//read file
    ...
	//Close file
	fclose(pf);
	pf = NULL;
	return 0;
}

Sequential reading and writing of files

fputc 

Demo code:

#include <stdio.h>

int main()
{
	//Open the data.txt file by writing
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen ");
		return;
	}
	//Output (write) content to the file
	fputc('h', pf);
	fputc('e', pf);
	fputc('l', pf);
	fputc('l', pf);
	fputc('o', pf);

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

After the program runs, it will find the file in the same directory. If the file does not exist, it will be created and the contents will be written into the file:

fgetc

Demo code: (take the contents of the above file as an example)

#include <stdio.h>

int main()
{
	//Open the data.txt file by writing
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen ");
		return;
	}
	char a = fgetc(pf);
	char b = fgetc(pf);
	char c = fgetc(pf);
	char d = fgetc(pf);
	char e = fgetc(pf);

	//Read the contents of the file one byte at a time
	printf("%c", a);
	printf("%c", b);
	printf("%c", c);
	printf("%c", d);
	printf("%c", e);

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

 

fputs 

Demo code:

#include <stdio.h>

int main()
{
	//Open file as write
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen ");
		return -1;
	}
	// Output (write) string to file
	char* str = "abcdefg";
	fputs(str, pf);

	//Close file
	fclose(pf);
	pf = NULL;

	return 0;
}

Similarly, the string will also be written to the file in the same directory.

fgets 

Demo code:

#include<stdio.h>
int main()
{
	//Open the file read-write
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen ");
		return -1;
	}

	// Input (read) the content from the file to the defined string
	char str2[10] = { 0 };
	fgets(str2, 7, pf);
	printf("%s", str2);
	//Close file
	fclose(pf);
	pf = NULL;

	return 0;
}

fwrite

Demo code:

#include <stdio.h>

int main()
{
	// Open file as write
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen ");
		return -1;
	}
	//Output content to file
	int  arr1[] = { 1,2,3,4,5 };
	fwrite(arr1, sizeof(arr1[0]), 5, pf);

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

The contents are written in binary form in the file

fread 

Demo code:

#include <stdio.h>

int main()
{
	// Open file read
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen ");
		return -1;
	}
	int arr[10] = { 0 };
	// Get the data from the file
	fread(arr, sizeof(arr[0]), 5, pf);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	//Close file
	fclose(pf);
	pf = NULL;
	return 0;
}

Program running results:

  

  Compare a set of functions:

scanf/fscanf/sscanf
printf/fprintf/sprintf

We are very familiar with scanf and printf, which are commonly used input and output functions.
fscanf is a function to fetch data from a file.
fprintf is a function that writes data into a file.

The sprintf function prototype is   int sprintf(char *str, const char *format, ...). The function is to format strings. The specific functions are as follows:

(1) Converts a numeric variable to a string.

(2) Get the hexadecimal and octal strings of integer variables.

The prototype of sscanf function is int sscanf(const char *str, const char *format,...). The string of parameter str is converted and formatted according to the parameter format string, and the converted result is stored in the corresponding parameter.

Examples of using sscanf and sprintf functions:

#include <stdio.h>

struct S
{
	int a;
	char b;
	char name[10];
};

int main()
{
	struct S s = { 10,'d',"zhangsan" };
	char arr[20] = { 0 };
	// Write structure data into string
	sprintf(arr, "%d %c %s", s.a, s.b, s.name);
	printf("%s\n", arr);
	
    // Take the data from the string and put it into the structure
	struct S p = { 0 };
	sscanf(arr, "%d %c %s", &(p.a), &(p.b), p.name);
	printf("%d %c %s\n", p.a, p.b, p.name);

	return 0;
}

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 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 );
    return 0;
} 

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

rewind

Returns 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);
    fread (buffer,1,26,pFile);
    fclose (pFile);
    buffer[26]='\0';
    puts (buffer);
    return 0;
}

Document end judgment

Misused 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 return value is less than the actual number to be read.

Correct use:
 

Examples of text files:

#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))//ferror returns 1 when the file is read incorrectly
    puts("I/O error when reading");
    else if (feof(fp))//Returns 1 when the file is read
    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;
}

Posted by AMV on Tue, 05 Oct 2021 15:03:26 -0700