File operation C language


1. What is a file?

Files on disk are files.
Computer files are a type of file. Different from ordinary file carriers, computer files are a collection of information stored on a computer using the computer hard disk as a carrier.

*Why use files

Using files, we can store data directly on the computer's hard drive, achieving data persistence.

——But in programming, we generally talk about two types of files: program files and data files:

program files

Including source program files (suffix .c), 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 is running, such as a file that needs to read data from when the program is running, or a file that outputs content.


2. File name

A file must have a unique file identifier so that users can identify and reference it.
The file name contains 3 parts: file path + file name trunk + file suffix
. For example: c:\code\test.txt
. For convenience, the file identifier is often called the file name.


3. File type

Depending on how the data is organized, data files are called text files or binary files .
The data is stored in binary form in the memory. If it is output to external memory without conversion, it is a binary file .
If it is required to be stored in ASCII code in external storage, it needs to be converted before storage. Files stored in the form of ASCII characters are text files .

How is data stored in memory?
Characters are always stored in ASCII form, and numerical data can be stored in either ASCII or binary form.
For example, if there is an integer 10000, if it is output to the disk in the form of ASCII code, it will occupy 5 bytes on the disk (one byte for each character), while if it is output in binary form, it will only occupy
4 bytes on the disk.
Insert image description here
Code test: (If you don’t understand here, you can read below to understand the file pointer)

#include <stdio.h>
int main()
{
    
    
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
	fclose(pf);
	pf = NULL;
	return 0;
}

Running result: (binary garbled code)
Insert image description here
can be interpreted using the method I found from the data:
Insert image description here
Result display:
Insert image description here

4. File buffer

The ANSIC standard uses a "buffer file system" to process data files. The so-called buffer file system means that the system automatically creates a "file buffer" in memory for each file being used in the program.
The data output from the memory to the disk will be sent to the buffer in the memory first, and then sent to the disk together after the buffer is filled.
If data is read from the disk to the computer, the data is read from the disk file and input into the memory buffer (the buffer is filled), and then the data is sent 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.

Buffer image example
Code example:

#include <stdio.h>
#include <windows.h>

int main()
{
    
    
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//先将代码放在输出缓冲区
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

Here we must focus on understanding the role of fflush;
when it first starts running for 10 seconds, there is no data in the opened file:
Insert image description here
after waiting for the program to run for 10 seconds, you will get:
Insert image description here
Insert image description here

5. File pointer (key points)

In the buffered file system, the key concept is the "file type pointer", referred to as the "file pointer".
Each used file opens up a corresponding file information area in the memory to store file-related information (such as file name, file status and 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 VS2013 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 contents of the FILE type of different C compilers are not exactly the same, but they are similar.
Whenever a file is opened, the system will automatically create a variable in the FILE structure based on the file's condition and fill in the information in it. The user does not need to care about the details
.
Generally, the variables of this FILE structure are maintained through a FILE pointer, which makes it more convenient to use.
Below we can create a pointer variable of FILE*:

FILE* pf;//文件指针变量

FILE
Define pf as a pointer variable pointing to FILE type data.
You can make pf point to the file information area of ​​a certain file (it is a structure variable).
The file can be accessed through the information in the file information area. In other words, the file associated
with it can be found through the file pointer variable . for example:

The file pointer points to

Opening and closing files

The file should be opened before reading or writing, and the file should be closed after use.
When writing a program, when a file is opened, a FILE* pointer variable pointing to the file will be returned, which is equivalent to establishing a relationship between the pointer and the file.
ANSIC stipulates that the 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 );

Open as follows:
Open method
Code example:

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

There are two ways to open the address of a file:

relative path

For example:

pFile = fopen ("myfile.txt","w");
pFile = fopen (".\\myfile.txt","w");//当前目录
pFile = fopen ("..\\myfile.txt","w");//上一级目录

absolute path

For example:

pFile = fopen ("C:nser\\Admin\\desktop\\myfile.txt","w");

Sequential reading and writing of files (difficulty)

standard input and output

Sequential read and write
write output
Insert image description here
Get characters from stream

Insert image description here
Write characters to stream

Insert image description here
Get string from stream

Insert image description here
Write string to stream

Code example:

#include <stdio.h>

int main()
{
    
    
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件
	int i = 0;
	for (i = 0; i < 26; i++)
	{
    
    
		fputc('a'+i, stdout);
	}

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

Here fputc will store the data in the text file data.txt. Legend:
operation result
There is also a simple application of fgetc:

#include<stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	int ch = fgetc(stdin);
	printf("%c\n", ch);
	ch = fgetc(stdin);
	printf("%c\n", ch);
	ch = fgetc(stdin);
	printf("%c\n", ch);
	ch = fgetc(stdin);
	printf("%c\n", ch);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

fgetc will read characters from the previous data.txt text file, and after each reading, fgetc will point to the next character and read it in sequence, such as the following figure:

Insert image description here
fputs code example:

#include<stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "w");
	if (NULL == pf)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件 - 写一行
	fputs("hello bit\n", pf);
	fputs("hello xiaobite\n", pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

fputs will print the two read strings on the same line.
Insert image description here
Change the content in data.txt to:Insert image description here

fgets will read a string of specified size from the second, code example:

#include<stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (NULL == pf)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件 - 读一行
	char arr[10] = {
    
     0 };
	fgets(arr, 10, pf);
	printf("%s", arr);
	fgets(arr, 10, pf);
	printf("%s", arr);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

Code running results:
Insert image description here

Compare a set of functions:

scanf/fscanf/sscanf

Insert image description here
Read formatted data from stdin

Insert image description here
Read formatted data from stream

Insert image description here
Read formatted data from string

printf/fprintf/sprintf

Insert image description here
Print formatted data to standard output

Insert image description here
Write formatted data to stream

Insert image description here
Write formatted data to a string

fprintf code example:

#include<stdio.h>
struct S
{
    
    
	int a;
	float s;
};

int main()
{
    
    
	FILE* pf = fopen("data.txt", "w");
		if (NULL == pf)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件
	struct S s = {
    
     100, 3.14f };
	fprintf(pf, "%d %f", s.a, s.s);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

Code running results:
Insert image description here
fscanf code example:

#include<stdio.h>
struct S
{
    
    
	int a;
	float s;
};

int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (NULL == pf)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件
	struct S s = {
    
    0};
	fscanf(pf, "%d %f", &(s.a), &(s.s));

	fprintf(stdout, "%d %f", s.a, s.s);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

Insert image description here

sprintf code example:

#include<stdio.h>
struct S
{
    
    
	int a;
	float s;
	char str[10];
};

int main()
{
    
    
	char arr[30] = {
    
     0 };
	struct S s = {
    
     100, 3.14f, "hehe" };
	sprintf(arr, "%d %f %s", s.a, s.s, s.str);
	printf("%s\n", arr);
	return 0;
}

Running results:
Insert image description here
sscanf code example:

#include<stdio.h>
struct S
{
    
    
	int a;
	float s;
	char str[10];
};

int main()
{
    
    
	char arr[30] = {
    
     0 };
	struct S s = {
    
     100, 3.14f, "hehe" };
	struct S tmp = {
    
    0};

	sprintf(arr, "%d %f %s", s.a, s.s, s.str);
	sscanf(arr, "%d %f %s", &(tmp.a), &(tmp.s), tmp.str);
	printf("%d %f %s\n", tmp.a, tmp.s, tmp.str);
	return 0;
//}

Code running result:
Insert image description here
Insert image description here
write data block to stream

Insert image description here
Read chunks of data from the stream

fwrite code demonstration:

#include<stdio.h>
struct S
{
    
    
	int a;
	float s;
	char str[10];
};

int main()
{
    
    
	struct S s = {
    
     99, 6.18f, "bit" };

	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//写文件
	fwrite(&s, sizeof(struct S), 1, pf);

	fclose(pf);
	pf = NULL;

	return 0;
}

Code running result:
Insert image description here
This is a binary result, so the display is garbled; however, fread can be called to read
the code demonstration:

#include<stdio.h>
struct S
{
    
    
	int a;
	float s;
	char str[10];
};

int main()
{
    
    
	struct S s = {
    
     0 };

	FILE* pf = fopen("data.txt", "rb");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	fread(&s, sizeof(struct S), 1, pf);
	printf("%d %f %s\n", s.a, s.s, s.str);

	fclose(pf);
	pf = NULL;

	return 0;
}

operation result:
Insert image description here

Random reading and writing of files

fseek
locates the file pointer based on its position and offset.

Insert image description here

Reposition the stream position indicator

example:

First change the data in data.txt as shown below:
Insert image description here

/* fseek example */
#include <stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	//定位文件指针到f
	fseek(pf, 5, SEEK_SET);//从起始位置开始
    int	ch = fgetc(pf);
	printf("%c\n", ch);

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

}

Code running results:
Insert image description here

#include <stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	//定位文件指针到f
	fseek(pf, -4, SEEK_END);//从末尾位置开始
    int	ch = fgetc(pf);
	printf("%c\n", ch);

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

}

operation result:
Insert image description here

#include <stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	//定位文件指针到f
	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


	fseek(pf, 2, SEEK_CUR);
	ch = fgetc(pf);
	printf("%c\n", ch);

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

Running result:
Insert image description here
Insert image description here
Get the current position in the stream, (calculate offset)

Code example:

#include <stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	//定位文件指针到f
	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


	int pos = ftell(pf);
	printf("%d\n", pos);

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

operation result:
Insert image description here

Insert image description here
Set the position of the stream to the beginning (return to the starting position)

Code demo:

#include <stdio.h>
int main()
{
    
    
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("fopen");
		return 1;
	}
	//读文件
	//定位文件指针到f
	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

	rewind(pf);

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

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

operation result:
Insert image description here

6. Determination of file end

incorrectly used feof

Remember: During the file reading process, the return value of the feof function cannot be used directly to determine whether the file is ended.
Instead, it is used when the file reading ends to determine whether the reading failed or the end of the file was encountered .

  1. Whether the text file reading is completed, determine 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. The reading end judgment of the binary file determines 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:

Text file example

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    
    
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
    
    
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   {
    
     
       putchar(c);
   }
 //判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

Binary file example

#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"); // 必须用二进制模式
    fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
    fclose(fp);
    fp = fopen("test.bin","rb");
    // 读 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;
}

Here I will introduce another code for copying files:

//拷贝文件
//拷贝data1.txt 文件,产生一个新的文件data2.txt
#include<stdio.h>
int main()
{
    
    
	FILE* pfRead = fopen("data1.txt", "r");//打开data1.txt
	if (pfRead == NULL)
	{
    
    
		perror("open file for read");
		return 1;
	}
	FILE* pfWrite = fopen("data2.txt", "w");//打开data2.txt
	if (pfWrite == NULL)
	{
    
    
		perror("open file for write");
		fclose(pfRead);
		pfRead = NULL;
		return 1;
	}
	//读写文件
	int ch = 0;
	while ((ch = fgetc(pfRead)) != EOF)//将data1.txt中的代码依次复制到data2.txt中
	{
    
    
		fputc(ch, pfWrite);
	}

	//关闭文件
	fclose(pfRead); 
	pfRead = NULL;
	fclose(pfWrite);
	pfWrite = NULL;

	return 0;
}

Summarize

In short, the content of this chapter of file operation is very complicated. I hope you can study it carefully and master it as soon as possible;

Guess you like

Origin blog.csdn.net/mdjsmg/article/details/131795142