第九章学习笔记
一、知识点归纳
0.云班课中的提问
文件操作都有什么?
文件操作涵盖了对文件的创建、打开、读取、写入、关闭等基本操作。这些操作可以在计算机程序中对文件进行处理、管理和维护。
常见的文件操作包括:
-
创建文件:创建新的空文件或覆盖已存在的文件。
-
打开文件:打开已存在的文件,以便读取或写入数据。
-
读取文件:从文件中读取数据到程序中。
-
写入文件:将程序中的数据写入到文件中。
-
关闭文件:关闭文件,释放程序对文件的控制,确保数据写入文件。
-
重命名和移动文件:更改文件名或将文件移动到新位置。
-
删除文件:从文件系统中删除指定的文件。
进制文件和文本文件如何转换?
二进制文件和文本文件之间的转换通常涉及到文件中数据的编码和解码过程。
下面是一些常见的方法来实现二进制文件和文本文件之间的转换:
-
文本到二进制:
-
手动编码:将文本文件中的每个字符或行转换为二进制数据,并将其写入二进制文件。这需要你定义数据的编码方式,如将字符映射到ASCII码或使用其他编码格式。
-
使用编码库:许多编程语言提供了编码和解码文本数据的库。例如,Python提供了
encode
和decode
方法,可以将文本数据编码成二进制,然后再解码回文本。
-
-
二进制到文本:
-
手动解码:从二进制文件中读取数据,并根据你的编码规则将其解码为文本数据。这通常需要你了解数据的结构和编码方式。
-
使用解码库:许多编程语言也提供了解码二进制数据的库。例如,Python的
decode
方法可以将二进制数据解码成文本数据。
-
)
数据结构如何读写?
读写数据结构通常涉及将数据结构的内容从内存写入文件,然后从文件中读取数据并还原为数据结构。这个过程需要考虑数据结构的组织方式以及如何将其序列化(写入)和反序列化(读取)。
以下是读写数据结构的一般步骤:
-
序列化数据结构:
-
序列化是将数据结构的内容转换为可以写入文件的格式。这涉及将数据结构的各个字段以一种特定的顺序编码成字节序列,通常以二进制形式。
-
对于文本文件,你可以选择将数据以某种可读性良好的格式编码,例如JSON或XML,以便查看和编辑。
-
-
写入数据到文件:
-
打开文件以供写入,通常以二进制模式(
"wb"
)打开,如果是文本数据,则使用文本模式("w"
)。 -
使用文件I/O函数将序列化后的数据写入文件。对于二进制文件,可以使用
fwrite
函数(在C语言中),对于文本文件,可以使用fprintf
或类似的函数。
-
-
反序列化数据结构:
- 反序列化是将文件中的数据还原为数据结构的过程。这涉及读取文件中的数据并解码它以还原数据结构。
-
从文件读取数据:
-
打开文件以供读取,通常以二进制模式(
"rb"
)打开,如果是文本数据,则使用文本模式("r"
)。 -
使用文件I/O函数从文件中读取数据。对于二进制文件,可以使用
fread
函数(在C语言中),对于文本文件,可以使用fscanf
或类似的函数。
-
-
将数据还原为数据结构:
- 使用反序列化过程,将从文件中读取的数据还原为原始数据结构。这通常需要了解数据的结构和编码方式。
1.I/O库函数与系统调用
I/O库函数和系统调用是Unix/Linux系统编程中处理输入和输出的两种不同方法,它们有一些区别和共同点:
** I/O库函数(Standard I/O)**:
-
高级抽象:I/O库函数提供了高级抽象,以更容易地进行文件操作。它们使用缓冲区管理数据,提供了更方便的接口,例如
fopen
、fclose
、fread
、fwrite
等。 -
缓冲:I/O库函数通常使用内部缓冲区来提高性能,减少对底层文件的频繁访问。这意味着数据可能不会立即写入磁盘,而是在缓冲区满或者手动刷新时才会被写入。
-
跨平台:I/O库函数是标准C库的一部分,因此在不同的Unix/Linux系统上具有跨平台性。
-
与文件描述符无关:I/O库函数通常不直接与文件描述符交互,而是通过
FILE
结构来管理文件。
系统调用:
-
低级操作:系统调用提供了对底层操作系统功能的直接访问,它们是操作系统提供的API,用于文件操作,如
open
、read
、write
、close
等。 -
无缓冲:系统调用通常不使用内部缓冲,数据直接传输到文件或设备,因此更适用于需要精确控制I/O的情况。
-
性能:由于系统调用更接近底层,它们通常具有更好的性能,特别是在需要进行大量数据操作或需要实时性的情况下。
-
文件描述符:系统调用直接使用文件描述符来表示打开的文件,这些文件描述符可以在不同的系统调用之间共享。
总的来说,I/O库函数更适合用于一般文件操作和文本处理,因为它们提供了更高级的接口和缓冲机制,以提高开发效率。而系统调用更适合用于需要更底层控制、更高性能、或者与特定设备交互的情况。在实际编程中,可以根据具体需求选择使用哪种方法,有时也可以将它们结合起来以满足不同的需求。
2.I/O库函数的算法
-
fread:
fread
函数用于从文件中读取数据到内存缓冲区中。- 算法:
fread
会尝试从文件流中读取指定数量的数据块到内存缓冲区。它根据请求的数据块大小和数量来决定实际读取的字节数。 - 如果读取成功,返回实际读取的数据块数量(通常等于请求的数量)。如果到达文件末尾或发生错误,返回值可能小于请求的数量。
fread
会自动更新文件位置指针,以指向读取的下一个位置。
-
fwrite:
fwrite
函数用于将内存中的数据写入到文件中。- 算法:
fwrite
将指定数量的数据块从内存缓冲区写入到文件流中。它根据请求的数据块大小和数量来确定实际写入的字节数。 - 如果写入成功,返回实际写入的数据块数量(通常等于请求的数量)。如果发生错误,返回值可能小于请求的数量。
fwrite
会自动更新文件位置指针,以指向写入的下一个位置。
-
fclose:
fclose
函数用于关闭打开的文件流。- 算法:
fclose
会执行以下操作:- 将文件缓冲区中的剩余数据写入文件(如果是输出文件流)。
- 关闭文件句柄,释放与文件流相关的资源。
- 将文件流指针设置为 NULL,以防止进一步操作。
fclose
返回一个值,通常用于检查文件关闭是否成功。
3.I/O库模式
I/O库模式是指在进行文件操作时,文件流的打开模式,它决定了文件是用于读取、写入还是追加等操作。C标准库中提供了不同的模式来满足各种文件I/O需求。以下是一些常见的I/O库模式:
-
"r" 模式 (Read):
- 用于以只读模式打开文件。
- 如果文件不存在,会返回NULL。
- 文件位置指针位于文件的开头。
- 适用于读取文件内容。
-
"w" 模式 (Write):
- 用于以写入模式创建或打开文件,如果文件已存在则会被截断为空文件。
- 如果文件不存在,会创建一个新文件。
- 文件位置指针位于文件的开头。
- 适用于写入文件内容。
-
"a" 模式 (Append):
- 用于以追加模式打开文件,如果文件不存在则会创建一个新文件。
- 文件位置指针位于文件的末尾。
- 适用于在文件末尾追加数据而不覆盖现有内容。
-
"r+" 模式 (Read and Write):
- 用于以读写模式打开文件。
- 如果文件不存在,返回NULL。
- 文件位置指针位于文件的开头。
- 可以用于读取和写入文件内容。
-
"w+" 模式 (Write and Read):
- 用于以读写模式创建或打开文件,如果文件已存在则会被截断为空文件。
- 如果文件不存在,会创建一个新文件。
- 文件位置指针位于文件的开头。
- 可以用于读取和写入文件内容。
-
"a+" 模式 (Append and Read):
- 用于以读写模式打开文件,如果文件不存在则会创建一个新文件。
- 文件位置指针位于文件的末尾。
- 可以用于在文件末尾追加数据并读取文件内容。
-
字符模式I/O:
- 字符模式I/O是指以字符为单位进行输入和输出的操作,通常用于文本文件。例如,使用
fgetc
和fputc
函数来逐字符读取和写入文件。
- 字符模式I/O是指以字符为单位进行输入和输出的操作,通常用于文本文件。例如,使用
-
行模式I/O:
- 行模式I/O是指以行为单位进行输入和输出的操作,通常用于文本文件。使用函数如
fgets
和fputs
可以读取和写入整行文本。
- 行模式I/O是指以行为单位进行输入和输出的操作,通常用于文本文件。使用函数如
-
格式化I/O:
- 格式化I/O是指以特定格式读取和写入数据,通常用于处理各种数据类型,如整数、浮点数和字符串。使用函数如
fprintf
和fscanf
可以按照指定的格式进行输入和输出。
- 格式化I/O是指以特定格式读取和写入数据,通常用于处理各种数据类型,如整数、浮点数和字符串。使用函数如
-
内存中的转换函数:
- 这些函数允许将数据从内存中的一种表示形式转换为另一种表示形式,例如将整数转换为字符串或将字符串转换为浮点数。常见的函数包括
sprintf
(将格式化数据写入字符串)和sscanf
(从字符串中读取格式化数据)。
- 这些函数允许将数据从内存中的一种表示形式转换为另一种表示形式,例如将整数转换为字符串或将字符串转换为浮点数。常见的函数包括
-
其他I/O库函数:
- 除了上述提到的函数之外,C标准库还提供了许多其他I/O函数,用于处理文件、目录、错误处理等。例如,
remove
用于删除文件,rename
用于重命名文件,feof
用于检查文件流的结束标志等等。
- 除了上述提到的函数之外,C标准库还提供了许多其他I/O函数,用于处理文件、目录、错误处理等。例如,
-
限制混合fread-fwrite:
- 当混合使用
fread
和fwrite
时,需要小心处理文件位置指针。这两个函数使用不同的位置指针,并且在一个函数执行后可能会影响到另一个函数的结果。 - 如果你在读取后立即写入相同的文件,确保使用
fseek
或rewind
来重新设置文件位置指针,以确保正确的读写操作。 - 此外,要注意处理二进制和文本模式的差异,以避免在不同模式下出现问题。
- 当混合使用
4.文件流缓冲
文件流缓冲和变参函数是与C语言编程密切相关的两个概念,让我们一一解释它们:
文件流缓冲:
- 文件流缓冲是指在进行文件I/O操作时,数据通常会首先被读取到内存中的缓冲区,或者从缓冲区写入文件,而不是直接与文件进行每次读写操作。这个缓冲区的存在有助于提高I/O性能,因为将多个小的I/O操作合并成更大的块,减少了与磁盘的实际交互次数。
- C标准库中的文件操作函数通常都使用缓冲,默认情况下,标准I/O库会对文件进行全缓冲、行缓冲或无缓冲的处理,具体取决于文件的类型和打开模式。你可以使用
setvbuf
函数来手动设置文件的缓冲模式。
5.变参函数
变参函数(Variable Argument Functions):
- 变参函数是指能够接受可变数量的参数的函数。在C语言中,最常见的变参函数是使用
<stdarg.h>
头文件中的宏和函数来定义的。 stdarg.h
提供了一种机制,使函数能够接受不定数量的参数。常见的变参函数包括printf
和scanf
。- 在变参函数中,通常会使用
va_list
类型的对象来处理参数列表,使用va_start
来初始化参数列表的处理,使用va_arg
来访问参数,最后使用va_end
来结束参数列表的处理。
二、苏格拉底挑战
1.I/O库函数
2.I/O库函数的算法
三、问题与解决
1.GPT不能很好的联系上下文
解决方法主要是再向他重复一下上文情况,帮助他进行联系
2.GPT对于一些问题有理解偏差
此处我希望他提问的和他实际提问的方向不一致
解决方法跟上一个类似,都是向GPT提供更为详细的promote
3.GPT“胡说八道”
这里他的提问跟课本所讲知识方向不一致,所以我的回答并不算好,很多东西是直接向GPT再提问的,但是他总结的时候却说我答的很好,并且把他回答的东西当做是我提到的。
解决方面,目前GPT会胡说八道的这一特点已经不是秘密,很多时候这是一件好事,但是有些时候也不是,想要获得更“智能”的“人工智能”还是需要更多的promote。
四、实践过程以及代码截图
对于一个自定义的结构体person,使用文件I/O函数将这个结构体的实例写入文件或从文件中读取
将文本数据写入文本文件并将其从文本文件读取,以及如何将文本数据编码为二进制数据并从二进制文件解码: