catalogue
Sequential reading and writing of files
Random reading and writing of 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.
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; }