fread 和 fwrite 如何区分 C 语言中的不同数据(类型)?



我正在使用一个程序和C(使用Ubuntu及其bash(,并使用它来操作二进制数据文件。首先,当我使用fopen(filename, 'w')时,它会创建一个文件,但没有任何扩展名。但是,当我使用vim filename时,它会以某种二进制形式打开它。

对于这个问题,当我使用fwrite(array, sizeof(some struct), # of structs, filePointer)时,它会写入(我不确定二进制如何(写入文件。当我使用fread(anotherArray, sizeof(same struct), same # of structs, anotherFilePointer)时,它以某种方式神奇地知道如何以二进制形式读取每个结构,并通过知道它的大小和读取量将其放入数组中。如果我输入的十进制值小于# of structs参数中的结构数量,会发生什么情况?fread怎么知道正确阅读什么?它如何通过查看大小而不知道它是什么类型的数据来读取数据?

>fwrite将存储对象的内存的字节写入输出流,fread将输入流中的字节读取到作为参数获取地址的内存中。对于此内存中存储的 C 对象的类型和表示形式,不做任何假设。

因此,可能会出现许多问题:

  • 基本类型的表示形式可能因编译器而异,一台计算机与另一台计算机之间,一个操作系统与另一个操作系统之间可能不同,甚至可能取决于编译器开关。仅当您知道要将文件读回字节兼容结构时,写入基本类型的内存表示形式的字节才有意义。
  • 访问输入和输出文件的模式很重要:正如您所提到的,文件必须以二进制模式打开,以避免内存表示和文件内容之间的任何转换,例如旧系统上的文本文件发生的情况。例如,MS-Windows 上的文本模式会导致0A字节在输出时转换为0D0A个序列,在输入时0D字节被剥离,从而导致初始内容中隔离的0D字节的内容不同。
  • 如果 C 结构包含指针,则写入输出的字节表示这些指针的值,而不是它们指向的内容。将这些值读回内存中很可能会创建无效的指针,并且不太可能有任何意义。
  • 如果 C 结构末尾有一个灵活的数组,则其内容不包含在fwrite写入或fread读取的sizeof(T)字节中。
  • C 结构可能包含成员之间的填充,导致输出文件包含非确定性字节,这在某些情况下可能是个问题。
  • 如果 C 结构具有仅包含部分有意义内容的数组(例如包含 C 字符串的char数组(,请注意fwrite将写入超出 null 终止符的字节,这应该没有意义,但可能是敏感信息,例如密码片段或其他有意义的数据。仔细擦除此类数组可以避免此问题,但无法可靠地擦除填充字节,因此此解决方案并不完美。

由于上述所有原因和其他原因,读取/写入二进制数据应保留在程序员确切知道正在发生的事情的非常特殊的情况下。对于其他目的,最好以人类可读的形式另存为文本文件。

来自@David C. Rankin的评论

"好吧,read/fwrite 读写字节(二进制数据 - 如果你写出然后读取相同数量的字节 - 你会得到同样的东西(。如果你想读写文本,你需要担心换行符等,fgets/fputs。或 fprintf">

所以我想我永远无法知道我用fwriite读了什么,除非我知道我用fwriite写了什么?

"对,看看 fwrite(3( 中缓冲区的类型 - Linux 手册页是 void * 类型。它只是 fwrite 用于写入的起始地址,无论您告诉它写入多少字节。(显然你知道它在写什么(fread 也是如此——它只是读取字节——你必须知道你在读什么(或者至少它的格式(。这就是二进制I/O的意义所在,它都只是字节——这取决于你,程序员,知道你在写什么和读什么,以及如何解压缩它。否则,请使用格式化的 I/O 和行、单词等。

最新更新