c - 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
字节在输出时转换为0D
0A
序列,而字节在输入时被剥离,从而导致初始内容0D
中孤立字节的内容不同。0D
- 如果 C 结构包含指针,则写入输出的字节表示这些指针的值,而不是它们指向的值。将这些值读回内存很可能会创建无效指针,并且不太可能产生任何意义。
- 如果 C 结构末尾有一个灵活数组,则其内容不包含在由写入或读取的
sizeof(T)
字节中。fwrite
fread
- C 结构可能包含成员之间的填充,导致输出文件包含不确定的字节,这在某些情况下可能是一个问题。
- 如果 C 结构的数组只有部分有意义的内容,例如
char
包含 C 字符串的数组,请注意fwrite
将写入超出空终止符的字节,这应该没有意义,但可能是敏感信息,例如密码片段或其他有意义的数据。仔细擦除此类数组可能会避免此问题,但填充字节无法可靠擦除,因此此解决方案并不完美。
由于上述所有原因和其他原因,读取/写入二进制数据将保留给程序员确切知道发生了什么的非常特定的情况。出于其他目的,更倾向于以人类可读的形式保存为文本文件。
推荐阅读
- mongodb - 用于匹配的 Mongo 聚合,其中两个数组值之间的差异在 X 和 Y 之间
- html - Bootstrap4 Modal Body 不让 div 拉伸 100% 高度
- java - 为什么从第一个字符串数组解析数据时抛出异常,但跳过第一个数组时却没有?
- python - 生成多个敌人 pygame
- kubernetes - kubernetes pod 容器通过 CrashLoopBackoff 不断重启
- database - 如何使用 MongoDB 实现 SELECT ... FOR UPDATE 和 Transactions 水平扩展服务?
- javascript - 每次更新状态时如何渲染元素
- visual-studio-code - VSCode 不会为 nextjs (9.5.2) 绑定客户端断点
- reactjs - 我想在下拉菜单上显示标题,当有人选择一个选项并提交时,我想提交年份值
- sql - BigQuery - 连接列的所有行,直到达到特定值