C 进阶 — 文件操作

server/2024/12/26 10:58:18/

C 进阶 — 文件操作

主要内容
  1. 文件概述
  2. 文件打开和关闭
  3. 文件顺序读写
  4. 文件随机读写
  5. 文本文件和二进制文件
  6. 文件缓冲区

一 文件概述

1.1 使用文件的原因

例 先前通讯录程序,数据存放在内存中,当程序退出时,通讯录中的数据自然就不存在了。如何把信息记录下来?一般数据持久化的方法有,数据存放在磁盘文件、存放到数据库等方式。使用文件将数据直接存放在电脑的硬盘上

1.2 什么是文件

磁盘上的文件即是文件

但程序设计中的文件一般指两种:程序文件、数据文件(从文件功能角度分类)

程序文件

包括源程序文件( 后缀为.c ),目标文件( windows 环境后缀为 .obj ),可执行程序( windows 环境后缀为 .exe )

数据文件

程序运行时读写的数据,以前章节所处理数据输入输出都是以终端为对象( 从终端的键盘输入数据,运行结果显示到显示器上 )

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

文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。文件名包含三部分 :文件路径+文件名主干+文件后缀,例如: c:\code\test.txt,为方便文件标识常被称为 文件名

二 文件打开和关闭

2.1 文件指针

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

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

例如,VS 编译环境提供的 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 结构变量

创建一个 FILE* 指针变量

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

定义 pf 是一个指向 FILE 类型数据的指针变量,使 pf 指向某个文件的文件信息区(一个结构体变量)。通过该文件信息区中的信息能够访问该文件,即通过文件指针变量找到与它关联的文件,如下图

image-20241216234248994

2.2 文件打开和关闭

文件在读写前应先打开文件,在使用结束后应关闭文件

在打开文件时,会返回一个 FILE* 指针变量指向该文件(建立指针和文件的关系)

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

//打开文件
FILE * fopen ( const char * filename, const char * mode );//关闭文件
int fclose ( FILE * stream );

打开方式如下

文件使用方式 含义 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
“w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
“a”(追加) 向文本文件尾添加数据 建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件 出错
“wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据 建立一个新的文件
“r+”(读写) 为了读和写,打开一个文本文件 出错
“w+”(读写) 为了读和写,建议一个新的文件 建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件 出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件

实例代码

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

三 文件顺序和随机读写

在编程中,(Stream)是一种用来顺序传输数据的抽象,数据可以是输入的(如从键盘、文件或网络读取)或者是输出的(如打印到屏幕或写入文件)

C 中的流是通过标准库实现的

流的分类

1、标准输出流(stdin):用于接收用户输入,类似键盘输入这种,默认缓冲方式为行缓冲,即当检测到换行符或缓冲区满时会提交数据

2、标准输入流(stdout):用于输出到屏幕,默认缓冲方式也为行缓冲

3、标准错误流(stderr):用于输出错误信息,一般采取立即输出的方式

3.1 顺序读写函数

功能 函数名 适用于
字符输入函数 fgetc 所有输入流
字符输出函数 fputc 所有输出流
文本行输入函数 fgets 所有输入流
文本行输出函数 fputs 所有输出流
格式化输入函数 fscanf 所有输入流
格式化输出函数 fprintf 所有输出流
二进制输入 fread 文件
二进制输出 fwrite 文件
3.1.1 流中获取字符 fgetc
int fgetc ( FILE * stream );
Returns the character currently pointed by the internal file position indicator of the specified stream. The internal file position indicator is then advanced to the next character.
返回指定流的内部文件位置指示器当前指向的字符。然后,内部文件位置指示器前进到下一个字符If the stream is at the end-of-file when called, the function returns EOF and sets the end-of-file indicator for the stream (feof).
如果调用时流位于文件末尾,则函数将返回 EOF 并设置流的文件结束指示器 (feof)If a read error occurs, the function returns EOF and sets the error indicator for the stream (ferror).
如果发生读取错误,该函数将返回 EOF 并为流设置错误指示符 (ferror)fgetc and getc are equivalent, except that getc may be implemented as a macro in some libraries.
fgetc 和 getc 是等效的,只是 getc 在某些库中可能作为宏实现

代码示例

/* fgetc example: money counter */
#include <stdio.h>
int main ()
{FILE * pFile;int c;int n = 0;pFile=fopen ("myfile.txt","r");if (pFile==NULL) perror ("Error opening file");else{do {c = fgetc (pFile);if (c == '$') n++;} while (c != EOF);fclose (pFile);printf ("The file contains %d dollar sign characters ($).\n",n);}return 0;
}
3.1.2 将字符写入流 fputc
int fputc ( int character, FILE * stream );
Writes a character to the stream and advances the position indicator.
将字符写入流并前进位置指示器The character is written at the position indicated by the internal position indicator of the stream, which is then automatically advanced by one.
字符被写入流的内部位置指示器指示的位置,然后自动前进 1

代码示例

/* fputc example: alphabet writer */
#include <stdio.h>int main ()
{FILE * pFile;char c;pFile = fopen ("alphabet.txt","w");if (pFile!=NULL) {for (c = 'A' ; c <= 'Z' ; c++)fputc ( c , pFile );fclose (pFile);}return 0;
}
3.1.3 从流中获取字符串 fgets
char * fgets ( char * str, int num, FILE * stream );
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
从 stream 中读取字符并将其作为 C 字符串存储到 str 中,直到读取 (num-1) 个字符,或者到达换行符或文件末尾,以先发生者为准A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str.
换行符会 fgets 停止读取,但它会被函数视为有效字符,并包含在复制到 str 的字符串中A terminating null character is automatically appended after the characters copied to str.
终止 null 字符会自动附加到复制到 str 的字符之后Notice that fgets is quite different from gets: not only fgets accepts a stream argument, but also allows to specify the maximum size of str and includes in the string any ending newline character.
请注意,它与 gets 完全不同:fgets 不仅接受 stream 参数,还允许指定 str 的最大大小,并在字符串中包含任何结束换行符

代码示例

/* fgets example */
#include <stdio.h>int main()
{FILE * pFile;char mystring [100];pFile = fopen ("myfile.txt" , "r");if (pFile == NULL) perror ("Error opening file");else {if ( fgets (mystring , 100 , pFile) != NULL )puts (mystring);fclose (pFile);}return 0;
}
3.1.4 将字符串写入流 fputs
int fputs ( const char * str, FILE * stream );
Writes the C string pointed by str to the stream.
将 str 指向的 C 字符串写入流The function begins copying from the address specified (str) until it reaches the terminating null character ('\0'). This terminating null-character is not copied to the stream.
该函数从指定的地址 (str) 开始复制,直到到达终止 null 字符 ( '\0' )。此终止 null 字符不会复制到流中Notice that fputs not only differs from puts in that the destination stream can be specified, but also fputs does not write additional characters, while puts appends a newline character at the end automatically.
请注意,它 fputs 不仅与 puts 的不同之处在于可以指定目标流,而且 fputs 不会写入其他字符,而 puts 会自动在末尾附加换行符

代码示例

/* fputs example */
#include <stdio.h>int main ()
{FILE * pFile;char sentence [256];printf ("Enter sentence to append: ");fgets (sentence,256,stdin);pFile = fopen ("mylog.txt","a");fputs (sentence,pFile);fclose (pFile);return 0;
}
3.1.5 从流中读取格式化数据 fscanf
int fscanf ( FILE * stream, const char * format, ... );
Reads data from the stream and stores them according to the parameter format into the locations pointed by the additional arguments.
从流中读取数据,并根据参数格式将其存储到其他参数指向的位置The additional arguments should point to already allocated objects of the type specified by their corresponding format specifier within the format string.
其他参数应指向已分配的对象,该对象由格式字符串中的相应格式说明符指定的类型

代码示例

/* fscanf example */
#include <stdio.h>int main ()
{char str [80];float f;FILE * pFile;pFile = fopen ("myfile.txt","w+");fprintf (pFile, "%f %s", 3.1416, "PI");rewind (pFile);fscanf (pFile, "%f", &f);fscanf (pFile, "%s", str);fclose (pFile);printf ("I have read: %f and %s \n",f,str);return 0;
}
3.1.6 将格式化数据写入流 fprintf
int fprintf ( FILE * stream, const char * format, ... );
Writes the C string pointed by format to the stream. If format includes format specifiers (subsequences beginning with %), the additional arguments following format are formatted and inserted in the resulting string replacing their respective specifiers.
将 format 指向的 C 字符串写入流。如果 format 包含格式说明符(子序列以 开头), % 则 format 后面的其他参数将被格式化并插入到结果字符串中,以替换其各自的说明符After the format parameter, the function expects at least as many additional arguments as specified by format.
在 format 参数之后,该函数至少需要与 format 指定的相同数量的附加参数

代码示例

/* fprintf example */
#include <stdio.h>int main ()
{FILE * pFile;int n;char name [100];pFile = fopen ("myfile.txt","w");for (n=0 ; n<3 ; n++){puts ("please, enter a name: ");gets (name);fprintf (pFile, "Name %d [%-10.10s]\n",n+1,name);}fclose (pFile);return 0;
}

示例代码,对格式化的数据进行文件读写

#include <stdio.h>
struct S
{char arr[10];int num;float sc;
};int main()
{struct S s = { "abcdef", 10, 5.5f };//对格式化的数据进行写文件FILE*pf = fopen("test.dat", "w");if (NULL == pf){perror("fopen");return 1;}//写文件fprintf(pf, "%s %d %f", s.arr, s.num, s.sc);//关闭文件fclose(pf);pf = NULL;return 0;
}int main()
{struct S s = {0};//对格式化的数据进行写文件FILE* pf = fopen("test.dat", "r");if (NULL == pf){perror("fopen");return 1;}//读文件fscanf(pf, "%s %d %f", s.arr, &(s.num), &(s.sc));//打印fprintf(stdout, "%s %d %f\n", s.arr, s.num, s.sc);//关闭文件fclose(pf);pf = NULL;return 0;
}

puts 将字符串写入 stdout

Writes the C string pointed by str to the standard output (stdout) and appends a newline character ('\n').
将 str 指向的 C 字符串写入标准输出 (stdout) 并附加换行符 ( '\n' )The function begins copying from the address specified (str) until it reaches the terminating null character ('\0'). This terminating null-character is not copied to the stream.
该函数从指定的地址 (str) 开始复制,直到到达终止 null 字符 ( '\0' ),此终止 null 字符不会复制到流中Notice that puts not only differs from fputs in that it uses stdout as destination, but it also appends a newline character at the end automatically (which fputs does not).
请注意,它与 puts fputs 的不同之处在于它使用 stdout 作为目标,而且还会自动在末尾附加一个换行符(而 fputs 则不会)

gets 从 stdin 获取字符串

[NOTE: This function is no longer available in C or C++ (as of C11 & C++14)]
[注意:此功能在C或C++中不再可用(从C11和C++14开始)]Reads characters from the standard input (stdin) and stores them as a C string into str until a newline character or the end-of-file is reached.
从标准输入 (stdin) 中读取字符,并将其作为 C 字符串存储到 str 中,直到到达换行符或文件末尾The newline character, if found, is not copied into str.
如果找到换行符,则不会将其复制到 str 中A terminating null character is automatically appended after the characters copied to str.
终止 null 字符会自动附加到复制到 str 的字符之后Notice that gets is quite different from fgets: not only gets uses stdin as source, but it does not include the ending newline character in the resulting string and does not allow to specify a maximum size for str (which can lead to buffer overflows).
请注意,这与 fgets 完全不同:不仅 gets 使用 stdin 作为源,而且它在结果字符串中不包含结束换行符,并且不允许指定 str 的最大大小(这可能导致缓冲区溢出)
3.1.7 二进制输入 fread
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
Reads an array of count elements, each one with a size of size bytes, from the stream and stores them in the block of memory specified by ptr.
从流中读取 count 元素数组,每个元素的大小为 size 字节,并将它们存储在 ptr 指定的内存块中The position indicator of the stream is advanced by the total amount of bytes read
流的位置指示器按读取的总字节数前进。The total amount of bytes read if successful is (size*count).
如果成功,则读取的总字节数为 (size*count) 

代码示例

struct S
{char arr[10];int num;float sc;
};int main()
{struct S s = { "abcde", 10, 5.5f };//二进制的形式写file*pf = fopen("test.dat", "w");if (pf == null){perror("fopen");return 1;}//写文件fwrite(&s, sizeof(struct s), 1, pf);//关闭文件fclose(pf);pf = null;return 0;
}
3.1.8 二进制读取 fwrite
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
Writes an array of count elements, each one with a size of size bytes, from the block of memory pointed by ptr to the current position in the stream.
将 count 元素数组(每个元素的大小为 size 字节)从 ptr 指向的内存块写入流中的当前位置The position indicator of the stream is advanced by the total number of bytes written.
流的位置指示器按写入的总字节数前进Internally, the function interprets the block pointed by ptr as if it was an array of (size*count) elements of type unsigned char, and writes them sequentially to stream as if fputc was called for each byte.
在内部,该函数将 ptr 指向的块解释为一个 (size*count) 元素的数组,该数组是 unsigned char 类型的 (size*count) 元素,并将它们按顺序写入 stream,就像 fputc 为每个字节调用一样

示例代码

struct S
{char arr[10];int num;float sc;
};int main()
{struct S s = {0};//二进制的形式读FILE*pf = fopen("test.dat", "r");if (pf == NULL){perror("fopen");return 1;}//读文件fread(&s, sizeof(struct S), 1, pf);printf("%s %d %f\n", s.arr, s.num, s.sc);//关闭文件fclose(pf);pf = NULL;return 0;
}

3.2 下列函数区别

3.2.1 输入函数

scanf / fscanf / sscanf

都支持读取格式化数据,但支持的数据源不一样。scanffscanf 的子集,scanf 仅针对于标准输入 stdinfscanf 针对于 File*,而 sscanf 仅针对于字符串 char* str

3.2.2 输出函数

printf/fprintf/sprintf 同上类似

四 文件随机读写

4.1 fseek

根据文件指针的位置和偏移量来定位文件指针

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

image-20241217124212490

代码示例

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

4.2 ftell

返回文件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );

代码示例

/* 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-portablesize=ftell (pFile);fclose (pFile);printf ("Size of myfile.txt: %ld bytes.\n",size);}return 0;
}

4.3 rewind

让文件指针的位置回到文件的起始位置

void rewind ( FILE * stream );

代码示例

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

五 文本文件和二进制文件

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

  1. 数据在内存中以二进制的形式存储,如果不加转换输出到外存 二进制文件
  2. 以 ASCII 字符形式存储的文件就是 文本文件

数据在内存中的存储

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

VS 查看二进制文件

image-20241217115938642

右键打开方式选择二进制

image-20241217120037616

image-20241217120137394

查看内存存储

image-20241217120258297

六 文件缓冲区

6.1 文件读取结束的判定

image-20241217121742009

  1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )

    例如:fgetc 判断是否为 EOF ,fgets 判断返回值是否为 NULL

  2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数

    例如:fread 判断返回值是否小于实际要读的个数

错误使用的 feof(在文件读取过程中,不能用 feof 函数返回值直接来判断文件是否结束),feof 作用:当文件读取结束时,判断读取结束的原因是错误或到文件末尾

代码示例

//文本文件例子
#include <stdio.h>
#include <stdlib.h>
int main(void)
{int c; // 注意:int,非 char,要求处理 EOFFILE* fp = fopen("test.txt", "r");if(!fp) {perror("File opening failed");return EXIT_FAILURE;}//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOFwhile ((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);
}//二进制文件例子
#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{double a[SIZE] = {1.,2.,3.,4.,5.};FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组fclose(fp);double b[SIZE];fp = fopen("test.bin","rb");size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 读 double 的数组if(ret_code == SIZE) {puts("Array read successfully, contents: ");for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);putchar('\n');} else { // error handlingif (feof(fp))printf("Error reading test.bin: unexpected end of file\n");else if (ferror(fp)) {perror("Error reading test.bin");}}fclose(fp);
}

6.2 文件缓冲区

ANSIC 标准采用 缓冲文件系统 处理数据文件,系统自动地在内存中为程序中每一个正在使用的文件开辟一块 文件缓冲区。从内存向磁盘输出数据会先送到内存中的缓冲区,缓冲区装满后一起写入磁盘。从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),再从缓冲区将数据送到程序数据区(程序变量等),缓冲区的大小右 C 编译器决定

image-20241217122540595

示例代码

#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
int main()
{FILE*pf = fopen("test.txt", "w");fputs("abcdef", pf); // 数据被放在输出缓冲区printf("打开 test.txt 文件, 睡眠 10 秒 \n");Sleep(10000); // 发现文件没有内容printf("刷新缓冲区 \n");fflush(pf); // 刷新缓冲区, 将输出缓冲区的数据写到文件(磁盘)printf("再睡眠 10 秒, 再次打开 test.txt 文件 \n");Sleep(10000); // 发现文件有内容fclose(pf);//注:fclose在关闭文件的时候,也会刷新缓冲区pf = NULL;return 0;
}

结论:因缓冲区存在 C 操作文件时,需刷新缓冲区或在操作结束时关闭文件,否则可能导致文件读写有问题


http://www.ppmy.cn/server/153291.html

相关文章

HDFS与HBase有什么关系?

1 、 HDFS 文件存储系统和 HBase 分布式数据库 HDFS 是 Hadoop 分布式文件系统。 HBase 的数据通常存储在 HDFS 上。 HDFS 为 HBase 提供了高可靠性的底层存储支持。 Hbase 是 Hadoop database ,即 Hadoop 数据库。它是一个适合于非结构化数据存储的数据库, HBase 基于列的…

GitCode 光引计划投稿 | GoIoT:开源分布式物联网开发平台

GoIoT 是基于Gin 的开源分布式物联网&#xff08;IoT&#xff09;开发平台&#xff0c;用于快速开发&#xff0c;部署物联设备接入项目&#xff0c;是一套涵盖数据生产、数据使用和数据展示的解决方案。 GoIoT 开发平台&#xff0c;它是一个企业级物联网平台解决方案&#xff…

【R语言遥感技术】“R+遥感”的水环境综合评价方法

R语言在遥感领域中是一个强大的工具&#xff0c;它提供了一系列的功能和优势&#xff0c;使得遥感数据的分析和应用更加高效和灵活。以下是R语言在遥感中的具体应用&#xff1a; 数据处理&#xff1a;R语言可以处理和清洗遥感数据&#xff0c;包括数据转换、滤波处理、去噪和数…

神经网络、深度学习、卷积神经网络

好的&#xff01;我会尽量详细且易懂地为你解释这些概念&#xff0c;并在最后用简单直白的语言总结一下。 1. 神经网络思想 神经网络是灵感来自于生物大脑神经元的工作原理&#xff0c;是一种模仿人类大脑处理信息的方式来设计的数学模型。我们的大脑由亿万个神经元组成&…

线性分类器(KNN,SVM损失,交叉熵损失,softmax)

KNN 工作机制 k-近邻算法的工作机制可以分为两个主要阶段&#xff1a;训练阶段和预测阶段。 训练阶段 在训练阶段&#xff0c;k-近邻算法并不进行显式的模型训练&#xff0c;而是简单地存储训练数据集。每个样本由特征向量和对应的标签组成。此阶段的主要任务是准备好数据&…

apisix的hmac-auth认证

目录 1、apisix的hmac认证Authorization头信息 2、signature的lua生成源码 3、java生成签证的简单示例 4、postman调用如下 apisix的hmac-auth认证&#xff0c;介绍可以看官方文档 hmac-auth | Apache APISIX -- Cloud-Native API Gateway 照着官方文档&#xff0c;发现生…

【Chrome】浏览器提示警告Chrome is moving towards a new experience

文章目录 前言一、如何去掉 前言 Chrome is moving towards a new experience that allows users to choose to browse without third-party cookies. 这是谷歌浏览器&#xff08;Chrome&#xff09;关于隐私策略更新相关的提示 提示&#xff1a;以下是本篇文章正文内容&…

CentOS7 安装MySQL

目录 一、准备工作 二、下载MySQL 三、安装MySQL 四、启动并配置MySQL 五、验证安装 六、修改mysql密码策略 七、MySQL配置允许远程连接 在CentOS 7系统上下载并安装MySQL&#xff0c;你可以按照以下步骤进行&#xff1a; 一、准备工作 检查并卸载MariaDB&#xff1a;…