首页 > 其他分享 >C语言——文件操作

C语言——文件操作

时间:2024-08-12 19:23:41浏览次数:11  
标签:文件 ch int C语言 pf printf 操作 txt

 数据持久化的方法:

1.把数据存放到磁盘文件 (使用文件可以将数据直接存放在电脑的硬盘上,做到数据的持久化)

2.存放到数据库 

什么是文件呢?磁盘上的文件就是文件。

在程序设计中,一般谈及的文件有两种,从文件功能的角度来分类,有:

1.程序文件:如  源程序文件(.h)      目标文件(windows环境后缀为.obj)   可执行程序(windows环境后缀为.exe)

2.数据文件:文件的内容不一定是程序,也可以是程序运行时读写的数据,如某个程序运行时需要从中读取数据的文件,或是输出内容的文件。

本篇博客主要讨论数据文件

        在开始的C语言学习时,我们所处理数据的输入输出都是以终端为对象的,如从终端的键盘输入数据,运行结果显示到显示器上。                      如图所示。

#include<stdio.h>
 
int main()
{
   int a=0;
   scanf("%d",&a);
   printf("%d",a);
   return 0;
}

       但有时候我们会把信息输出到磁盘上,当需要时再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件。

文件名:一个文件要有一个唯一的文件标识,以便用户识别和引用。方便起见,这个文件标识常被称为文件名。      如: C:\code\test.txt

文件名包括3部分: 文件路径  +  文件名主干  +文件后缀

                        如: C:\code\         test                .txt

注意:同一路径下不会出现同名文件。

文件的打开和关闭

文件指针

       缓冲文件系统中,关键的概念是文件类型指针,简称文件指针。

       每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字、文件状态、文件当前的位置等)。这些信息是保存在一个结构体变量中的,该结构体类型是由系统声明的,取名为FILE。

例如,VS2013编译环境提供的stdio.h头文件中就有以下的文件类型声明:

struct _iobuf
{
	char* _ptr;
	int _cnt;
	char* _base;
	int _flag;
	int _file;
	int _charbuf;
	int _bufsiz;
	char* _tmpfname;
};
typedef struct _iobuf FILE;

       不同的C编译器的FILE类型包含的内容不完全相同,但大同小异。

       当打开一个文件时,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。

       我们通常是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

打算读写(操作)一个文件时,会分为以下步骤:

1.打开文件

2.被打开的文件会维护一个文件信息区  

(如图所示,我们通常通过一个FILE的指针来维护这个FILE结构的变量

3.对文件进行读写等操作

4.关闭文件

        ANSIC规定使用fopen函数打开文件fclose函数关闭文件

fopen函数

filename:文件名       mode:打开模式

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错

“w”(只写)

为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据建立一个新的文件
“rb”(只读)为了输入数据,打开一个二进制文件出错

“wb”(只写)

为了输出数据,打开一个二进制文件建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据建立一个新的文件
“r+”(读写)为了读和写,打开一个文本文件出错

“w+”(读写)

为了读和写,建立一个新的文件建立一个新的文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开一个二进制文件出错

“wb+”(读写)

为了读和写,建立一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

例如,

FILE *pf=fopen("data.txt","w");

"w" 双引号括住 意味着传字符串,即传首地址。

       这段代码意思为,为了输出数据,以只写的方式打开一个名为“data.txt”的文本文件,如果该文件不存在,则会建立一个名为“data.txt”的新文件。

相对路径绝对路径

写文件名时分为相对路径绝对路径

一、相对路径:指在当前程序路径下

例如,

FILE* pf = fopen("data.txt", "w");

       如果当前路径下没有名为“data.txt”的文件,该代码执行时,会在当前路径下建立一个名为“data.txt”的新文件。

补充

1.              . \\  代表指向当前目录    (如上图所示)   (这里把  这个符号加粗方便辨认)

 如:     FILE* pf = fopen(".\\x64\\data.txt", "w");          .\\  指当前目录

该代码意思为,在当前目录的名为x64文件中,以只写的方式打开一个名为“data.txt”的文本文件。   
2.              .. \\  代表指向上一级目录    (如图所示)

 如:     FILE* pf = fopen("..\\练习\\data.txt", "w");                     ..\\  指上一级目录
该代码意思为,在当前目录上一级目录中的名为练习文件中,以只写的方式打开一个名为“data.txt”的文本文件。 

3.              同理,..\\..\\   代表指向上一级目录的上一级目录    

如:     FILE* pf = fopen("..\\..\\Contact\\data.txt", "w");//                    ..\\..\\指上一级目录的上一级

该代码意思为,在当前目录上一级目录上一级目录中的名为Contact文件中,以只写的方式打开一个名为“data.txt”的文本文件。 

二、绝对路径:指定其他位置路径

打开文件时,我们也可以打开其他位置路径的文件

例如:我们在桌面上创建一个data.txt,查看它的属性

  C:\Users\ASUS\Desktop\data.txt 就是它的文件名

FILE* pf = fopen("C:\\Users\\ASUS\\Desktop\\data.txt", "w");

该代码意思为,以只写的方式在桌面上打开一个名为“data.txt”的文本文件。 

(写   ‘\\’  是因为存在转义字符)  

fclose函数

#include<stdio.h>

int main()
{
    //打开文件
	FILE* pf = fopen("data.txt", "w");

	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

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

注意:打开文件后一定要记得关闭文件,同时把FILE类型的指针置空。

读写文件

       

读写文件分为   顺序读写    和   随机读写 (即指定位置读写)

文件的顺序读写

       首先思考一个问题,在读写文件时,首先要打开文件,再进行读写文件操作,那为什么使用scanfprintf时,我们没有打开键盘打开屏幕这些操作?

         因为C语言程序运行起来后,默认会打开3个流,也因此使用scanfprintf时无需考虑打开的问题。

1.标准输入流(stdin)      打开了这个流,才可以进行scanf、getchar等操作

2.标准输出流(stdout)    打开了这个流,才可以进行printf、putchar等操作

3.标准错误流(stderr)

三个流 的 类型皆为 FILE*             

       stdio.h是头文件的叫法,称之为标准输入输出,它针对的是键盘上输入把数据打印到屏幕上这些函数的总和。

       流是一个很抽象的概念,就如日常生活的水流,我们可以认为写程序处理的是数据流,在读数据和写数据时,计算机所涉及的外部设备是非常多的,就如输入时可以从键盘上输入、打开文件输入、使用摄像头输入数据,输出时可以打印到电脑屏幕上、可以打开文件输出、发送到网络上,我们会从不同的外部设备上面读数据,然后把数据输出到不同的外部设备上,而我们程序员不可能去学习各种各样外部设备的读写方式,因此流的概念应运而生,把数据流淌的过程抽象为流,要写数据时把数据写入流中,要读数据时把数据从流中读出,至于流如何与各种外部设备进行交互,我们无需去关心。

功能函数名适用于
字符输入函数fgetc所有输入流以文本形式进行操作
字符输出函数fputc所有输出流
文本行输入函数fgets所有输入流
文本行输出函数fputs所有输出流
格式化输入函数fscanf所有输入流
格式化输出函数fprintf所有输出流
二进制输入fread文件二进制读写
二进制输出fwrite文件

fputc函数

fputc函数:写字符到流中    

int main()
{
	
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	fputc('a', pf);   //'a'会传字符的ASCII码值
    fputc('b', pf);
    fputc('c', pf);
    int i = 0;
    for (i = 0; i < 10; i++)
    {
		fputc('a' + i, pf);
		fputc('a' + i, stdout);//写成stderr结果一样,出现在屏幕上
    }

	fclose(pf);
	pf = NULL;//置空
	return 0;
}

fgetc函数

fgetc函数:从流中获取字符
读取到字符,会返回字符的ASCII码值,读取失败或者遇到文件末尾时会返回EOF

int main()
{
	
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	int ch = fgetc(pf);
	printf("%c\n", ch);
    //文件指针默认打开文件时指向起始位置,读取完指针会默认往后走
	ch = fgetc(pf);
	printf("%c\n", ch);
	
	printf("%c\n", fgetc(stdin));//从键盘上读

	fclose(pf);
	pf = NULL;//置空

	return 0;
}

fputs函数

int main()
{
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}


    fputs("hello bit ", pf);
	fputs("hehehe\n", pf);//要换行需要自行添加\n
	fputs("hehehe", pf);

	fputs("hello wxcb", stdout);
	
	fclose(pf);
	pf = NULL;//置空
	return 0;
}

fgets函数

fgets函数:从流中读取最多num-1个(或者遇到换行就不读了)  最后一个为'\0'  
//  将stream指向的存到str指向的

//读取成功,则返回str的地址;读取失败,则返回NULL

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	
    char arr[10] = { 0 };
    fgets(arr, 10, pf);
    printf("%s\n", arr);
    
	fgets(arr, 10, pf);
    printf("%s", arr);

	fclose(pf);
	pf = NULL;//置空
	return 0;
}

fprintf函数

fprintf函数:将格式化的数据输出到文件中         //  ... 为可变参数

struct S
{
	int a;
	float s;
};

int main()
{
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}


	struct S s = { 100,3.14f };//   3.14默认是double类型  3.14f是float类型
	fprintf(pf, "%d  %f", s.a, s.s);

	fclose(pf);
	pf = NULL;//置空
	return 0;
}

fscanf函数

fscanf函数:从文件中读取格式化的数据到其他位置

struct S
{
	int a;
	float s;
};

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}


	struct S s = {0};
    fscanf(pf, "%d  %f", &(s.a), &(s.s));
    printf("%d  %f\n", s.a, s.s);

    fscanf(stdin, "%d  %f", &(s.a), &(s.s));//此时就相当于  scanf
    printf("%d  %f", s.a, s.s);
	
	fclose(pf);
	pf = NULL;//置空
	return 0;
}

补充:sprintf与sscanf函数

sprintf函数:把格式化数据转换成字符串

sscanf函数:从s字符串提取格式化数据放到后面 可变参数处

struct S
{
	int a;
	float s;
	char str[10];
};

int main()
{
  
	struct S s = { 100,3.14f,"hehe" };
	char arr[30] = { 0 };
	printf("%d %f %s\n", s.a, s.s, s.str);
	
	sprintf(arr, "%d %f %s", s.a, s.s, s.str);
	printf("%d %f %s\n", s.a, s.s, s.str);
	printf("%s\n", arr);
	printf("\n");
	
	struct S tmp = {0};
	sscanf(arr, "%d %f %s", &(tmp.a), &(tmp.s), &(tmp.str));
	printf("%s\n", arr);
	printf("%d %f %s\n", tmp.a, tmp.s, tmp.str);
	
	return 0;
}
scanf从标准输入流读取格式化的数据
printf向标准输出流写格式化的数据
fscanf适用于所有输入流的格式化输入函数
fprintf适用于所有输出流的格式化输出函数
sscanf从字符串中读取格式化的数据
sprintf将格式化的数据转换成字符串

fwrite函数

fwrite函数:从ptr指向的位置找 count 个大小为 size 的数据写到流中

count:元素个数    size:每个元素的字节数(byte)

struct S
{
	int a;
	float s;
	char str[10];
};

int main()
{
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}


	struct S s = { 99,6.18f,"bit" };
	fwrite(&s, sizeof(struct S), 1, pf);

	fclose(pf);
	pf = NULL;//置空
	return 0;
}

fread函数

fread函数:从流里读数据放到ptr所指的位置空间
size_t:返回的值为实际读到的数据的个数

struct S
{
	int a;
	float s;
	char str[10];
};

int main()
{
	FILE* pf = fopen("data.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}


	struct S s1 = { 0 };
	fread(&s1, sizeof(struct S), 1, pf);
	printf("%d %f %s", s1.a, s1.s, s1.str);

	fclose(pf);
	pf = NULL;//置空
	return 0;
}

文件的随机读写

fseek函数

fseek函数:根据文件指针的位置和偏移量来定位文件指针

stream:要定义的文件流    offset:偏移量   origin:起始位置

    如图所示为 文件“data.txt”

当打开文件时,文件指针默认指向文件的起始位置

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

	//fseek(pf, -4, SEEK_END);//从结束位置开始读    负数代表向右偏移
	//ch = fgetc(pf);
	//printf("%c\n", ch);

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

ftell函数

ftell函数:返回文件指针相对起始位置的偏移量

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}



	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

	printf("%d\n", ftell(pf));//此时的偏移量


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

rewind函数


rewind函数:让文件指针的位置回到文件的起始位置

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}


	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

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

	rewind(pf);
	ch = fgetc(pf);
	printf("%c\n", ch);//又变回了 a


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

文本文件和二进制文件

       根据数据的组织形式,数据文件被称为文本文件或者二进制文件

       数据在内存(程序运行所依赖的环境)中以二进制的形式存储,如果不加转换地输出到外存(即写到文件中去),就是二进制文件

(内存:程序运行所依赖的环境     外存:外部存储,硬盘)

       如果要在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

一个数据在内存中是怎么存储的?

1.字符一律以ASCII码值形式存储,ASCII码值是整数,就是以整数的二进制形式存储

2.数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。

        假设有个整数10000,如果以ASCII码的形式输出到磁盘, 则磁盘中占用5个字节(每个字符是一个字节) ,10000看作 字符1、字符0、字符0、字符0、字符0 五个字符的组合,放到文件中去,存的是每个字符的ASCII码值。这种存储方式是以文本的形式存进文件的,这种文件被称为文本文件

        不加任何转换,以二进制的形式,把10000的每一位当成一个字符,以数字字符的形式存到文件中去,这种文件被称为文本文件。

        而二进制形式输出,则在磁盘上只占4个字节(VS2013环境测试) 。10000 在内存中存储的是二进制的形式,把这个二进制的形式不加任何转换,直接写到文件中去,10000是个整数,占4个字节,这4个字节直接写到文件里去,文件里也只占4个字节。这个文件就被称为二进制文件

文件读取结束的判定

判断文件读取是否结束

1.文本文件

使用fgetc函数判断返回值是否为EOF

使用fgets函数判断返回值是否为NULL

2.二进制文件

使用fread函数判断返回值是否小于实际要读取的个数

feof函数

注意:在文件读取过程中,不能用feof函数的返回值 直接来判断文件是否结束   eof(end  of  file)

feof函数:当文件读取结束的时候,判断 是否 是因为 遇到了文件末尾 才 致使读取结束 的,就是已知读取结束了,用来分析具体原因的。

ferror函数

ferror函数:当文件读取结束的时候,判断 是否 是因为 发生了错误 才 致使读取结束 的,也是已知读取结束了,用来分析具体原因的。

文本文件读取的例子

int main()
{
	int ch = 0;//注意是int类型而不是char类型,要处理EOF
	FILE* pf = fopen("test.txt", "r");
	if (!pf)
	{
		perror("FILE opening failed");
		return 1;
	}

	while ((ch = fgetc(pf)) != EOF)//注意括号!!!
	{
		putchar(ch);
	}
	//判断是什么原因结束的
	if (feof(pf))
	{
		puts("End of file reached successfully");
	}
	else if (ferror(pf))//返回非0的值,说明读取遇到了错误
	{
		puts("I/O error when reading");
	}
	fclose(pf);
	pf = NULL;

	return 0;
}

实现文件的拷贝

//拷贝文件
int main()
{
	FILE* pfRead = fopen("data1.txt", "r");
	if (pfRead == NULL)
	{
		perror("open file for read");
		return 1;
	}

	FILE* pfWrite = fopen("data2.txt", "w");
	if (pfWrite == NULL)
	{
		perror("open file for write");
		fclose(pfRead);
		pfRead = NULL;
		return 1;
	}
	//读写文件
	int ch = 0;
	while ((ch = fgetc(pfRead)) != EOF)
	{
		fputc(ch, pfWrite);
	}

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

	return 0;
}

文件缓冲区

        ANSIC 标准是采用缓冲文件系统来处理数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小是由C编译系统决定的。  (硬盘即为文件)

#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);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
    //这里再次睡眠是因为fclose函数也会刷新缓冲区,为了证明是fflush刷新缓冲区的而不是fclose
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

标签:文件,ch,int,C语言,pf,printf,操作,txt
From: https://blog.csdn.net/2301_80342122/article/details/141073278

相关文章

  • Unity新输入系统 之 InputAction(输入配置文件最基本的单位)
    本文仅作笔记学习和分享,不用做任何商业用途本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正​首先你应该了解新输入系统的构成结构:Unity新输入系统结构概览-CSDN博客InputSystem-Unity手册1.InputAction概览还是需要强调,InputAction中定义了所......
  • 金蝶晕云星空表单插件:操作子单据体的删除触发父单据体的字段重算
    publicoverridevoidAfterDeleteRow(AfterDeleteRowEventArgse){base.AfterDeleteRow(e);if(e.EntityKey.Equals(asEntityKey))//子单据体标识{Entityentity=this.View.BillBusinessInfo.GetEntity(entityKey);intentryCurrentRowInde......
  • 金蝶云星空打开子界面后,子界面操作保存成功后关闭父窗体刷新父页面
     一、业务需求售后单界面点击按钮打开其他入界面,关闭其他入库单时是否刷新售后单,分两种情况:第一种:刷新:保存成功才刷新父窗体;第一次保存成功再次保存失败,刷新第二种:以下情况不刷新:不操作保存直接关闭其他入库单操作保存但是报错无法保存而关闭其他入库单 二、开发实......
  • mysql数据库:使用Python操作MySQL
    mysql数据库:使用Python操作MySQL安装第三方模块pymysqlpipinstallpymysql操作MySQLimportpymysql#创建连接#需要传入一些参数:#hostmysql所在的主机名或者是域名或者是ip地址#portmysql运行的端口号#ps-aux|grepmysql找到MySQL运行的进程......
  • 【待做】【文件传输系列】
    上传:从kali到windowscertutilpowershellIWRpowershellwgetcopy\\smbshare\xxxcurl下载:从windows到kali【flaskserver】:fromflaskimportFlask,requestapp=Flask(__name__)@app.route("/upload1",methods=["POST"])defsave_file1()......
  • 重头开始嵌入式第十八天(Linux系统编程 文件IO)
    Linux系统编程内容Linux系统编程涵盖了众多方面的知识和技术: 1. 文件I/O操作:包括打开、读取、写入、关闭文件,以及处理文件的权限、属性等。2. 进程管理:创建新进程、进程的终止、等待进程结束、进程的执行状态控制等。3. 信号处理:接收和处理系统发送的各种信号,以响......
  • 【漏洞复现】Crocus系统文件读取漏洞复现
    》》》漏洞描述《《《        Crocus系统旨在利用人工智能、高清视频、大数据和自动驾驶技术,帮助商用车减少交通事故和货物丢失,提高企业或车队的运营效率。其Download接口存在任意文件读取漏洞,未经身份验证攻击者可通过该漏洞读取系统重要文件。》》》信息收集《......
  • C语言典型例题36
    《C程序设计教程(第四版)——谭浩强》例题3.4输入一个字符,判别它是否为大写字母,如果是,将它转换为小写字母:如果不是,不转换。然后输出最后要输出的字符。代码://《C程序设计教程(第四版)——谭浩强》//例题3.4输入一个字符,判别它是否为大写字母,如果是,将它转换为小写字母:如果不......
  • 谷歌浏览器降级的方法-及chromedriver 下载文件
    为了适配python selenium使用chromedriver 对应当前谷歌浏览器,降级https://www.chromedownloads.net/chrome64win/#google_vignette这个地址为谷歌浏览器老版本的地址 http://chromedriver.storage.googleapis.com/index.html这个地址为谷歌浏览器对应的 chromedriver......
  • 【MySQL核心】数据恢复-批量修复 ibd 文件实战-拯救即将跑路的你
    简介本文章主要讲解MySQL异常宕机等意外情况下导致ibd文件损坏,配置mysql强制恢复(innodb_force_recovery)1-6级仍然无法启动的情况。下面是恢复整个实例的所有流程和思路。这里恢复的实例是mysql5.6的整个流程,5.7和5.6类似,8.0可以直接用ibd2sql进行坏表的恢......