在C语言中将结构体写入文件

4
我正在从事C/UNIX相关的工作,有一个包含多条记录的输入文件。我已将每个记录映射到一个结构体,并通过从数据库中添加缺失信息将该结构体写入输出文件。
我的问题是如何将这个由字符数组组成的结构体写回到文件中。我正在使用:
    fwrite(&record, sizeof(record), 1, out);
    fwrite("\n", 1, 1, outfd);

这将在每个成员后面写入一个终止的NULL '\0',请告诉我如何在不在每个成员后添加终止符'\0'的情况下将此结构写入文件。


2
请提供结构定义,以便我们知道您正在使用什么。此外,您正在尝试对刚刚编写的数据进行什么操作。如果它被写入另一个C程序中,这可能是一个特性。 - Seth Robertson
2
请注意,以这种方式进行操作意味着您的格式将无法移植。 - jamesdlin
2个回答

5
我想这些0是字符数组的一部分,它们位于每个C字符串的末尾。如果您需要在不包含0的情况下将字符串写入文件,则可以写入各个char数组,仅写入字符而不是尾随的零(您可以使用strlen()找到此长度),例如:

fwrite(theCharArray, 1, strlen(theCharArray), out);

但是,您可能需要向文件中写入有关每个字符串长度的一些信息。


谢谢Ernest,是的,那些尾随的'\0'是字符数组的一部分。写入单个字符串是唯一的解决方案吗?这个结构非常大,有100个成员。请给出建议。 - Sachin Chourasiya
1
@Jerry Coffin建议使用一个由offsetof计算出的值的数组和一个循环;这实际上会导致更多,尽管稍微简单一些的代码行。我能想到的一个疯狂的事情是,如果struct仅由char数组组成,则可以有一个for循环,迭代sizeof(struct)次,在每个步骤中推进指针,并将非零字符逐个写入文件。整个过程只需要几行代码,而且对于结构的修改也很健壮。缺点是性能可能不太好。 - Ernest Friedman-Hill

3
这将按照内存中存储的方式精确地写出一个record,但编译器可以在成员之间插入填充,并且如果这样做,它将写出那些填充字节中的任何值。
许多(大多数?)编译器有不可移植的方法来防止它们插入填充-MSVC使用#pragma pack(1),gcc使用__attribute(__packed__)(至少一些版本支持#pragma pack语法)。
还有可能你已经定义了record来包含一些零字节作为数据的一部分(例如,带有零终止符的char数组使它们成为字符串)。由于你没有展示record的定义,很难猜测是否适用于此情况。
编辑:根据你的评论,似乎后者是正确的。我要说的第一点是,删除它们可能不是一个好主意。如果你删除它们,你必须做一些事情来让读取数据的程序知道一个字段何时结束,下一个字段何时开始(除非字段是固定宽度的,可以隐式处理)。
最明显的可能性是在每个字段前面加上它的长度。这样做的优点是,如果/当您想要在文件中查找,您可以从一个字段转到下一个字段,而不必读取数据以查找终止字节。然而,通常我会使用索引-包含数据中连续记录的文件偏移量(可能还包括每个记录的关键数据,这样你就可以根据记录的内容快速搜索),所以你可以快速地寻找到一个记录的位置并读取它的数据。除非您有非常大的字段,否则寻找单个字段很少会有什么作用。

写入单个成员是消除此问题的唯一解决方案吗? - Sachin Chourasiya
1
@Sachin Chourasiya:基本上是的。但是,您可以使用offsetof创建一个偏移量数组来避免这种繁琐,以便您可以在循环中编写字段,而不是100个单独编写的fwrite(或puts等)调用。请参见:http://stackoverflow.com/questions/5088358/breaking-a-single-string-into-multiple-strings-c/5088496#5088496 以获取示例。 - Jerry Coffin
@Sachin:想象一下,如果你把 '\0'(以及其后面的字节)去掉了,你将如何识别下一个成员的开头? - pmg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接