C 使用fwrite/fread和数据结构的几个问题
我第一次使用C 使用fwrite/fread和数据结构的几个问题,c,data-structures,file-io,fread,fwrite,C,Data Structures,File Io,Fread,Fwrite,我第一次使用fwrite()和fread()将一些数据结构写入磁盘,我对最佳做法和正确的操作方法有几个问题 我在磁盘上写的是插入到图形结构中的所有用户配置文件(以便以后读取)。每个图形顶点的类型如下: typedef struct sUserProfile { char name[NAME_SZ]; char address[ADDRESS_SZ]; int socialNumber; char password[PASSWORD_SZ]; HashTa
fwrite()
和fread()
将一些数据结构写入磁盘,我对最佳做法和正确的操作方法有几个问题
我在磁盘上写的是插入到图形结构中的所有用户配置文件(以便以后读取)。每个图形顶点的类型如下:
typedef struct sUserProfile {
char name[NAME_SZ];
char address[ADDRESS_SZ];
int socialNumber;
char password[PASSWORD_SZ];
HashTable *mailbox;
short msgCount;
} UserProfile;
这就是我目前将所有配置文件写入磁盘的方式:
void ioWriteNetworkState(SocialNetwork *social) {
Vertex *currPtr = social->usersNetwork->vertices;
UserProfile *user;
FILE *fp = fopen("save/profiles.dat", "w");
if(!fp) {
perror("fopen");
exit(EXIT_FAILURE);
}
fwrite(&(social->usersCount), sizeof(int), 1, fp);
while(currPtr) {
user = (UserProfile*)currPtr->value;
fwrite(&(user->socialNumber), sizeof(int), 1, fp);
fwrite(user->name, sizeof(char)*strlen(user->name), 1, fp);
fwrite(user->address, sizeof(char)*strlen(user->address), 1, fp);
fwrite(user->password, sizeof(char)*strlen(user->password), 1, fp);
fwrite(&(user->msgCount), sizeof(short), 1, fp);
break;
currPtr = currPtr->next;
}
fclose(fp);
}
注意事项:
- 您看到的第一个
将在图形中写入用户总数,以便我知道需要读取多少数据fwrite()
用于测试目的。有成千上万的用户,我仍在试验代码李>中断
- 阅读之后,我决定对每个元素使用
,而不是编写整个结构。我还避免将指针写入邮箱,因为我不需要保存该指针。那么,这就是路吗?多个fwrite()
,而不是整个结构的全局?不是慢了点吗fwrite()
- 如何读回此内容?我知道我必须使用
但是我不知道字符串的大小,因为我使用fread()
来编写它们。我可以在写入字符串之前写入strlen()的输出,但是没有额外的写入,还有更好的方法吗strlen()
- 它比较慢。调用函数x次比在x>1时调用一次要慢。如果性能是一个问题,您可以使用sizeof(结构)的
/fwrite
进行常规使用,并编写可移植的序列化版本进行导入/导出。但首先要检查这是否真的是个问题。大多数格式不再使用二进制数据,因此您可以看出,至少性能不是他们主要关心的问题fread
- 不,没有。另一种方法是使用基于
的strlenfgetc(3)
- 它比较慢。调用函数x次比在x>1时调用一次要慢。如果性能是一个问题,您可以使用sizeof(结构)的
/fwrite
进行常规使用,并编写可移植的序列化版本进行导入/导出。但首先要检查这是否真的是个问题。大多数格式不再使用二进制数据,因此您可以看出,至少性能不是他们主要关心的问题fread
- 不,没有。另一种方法是使用基于
的strlenfgetc(3)
此外,无论您选择何种格式,请确保您考虑将来可能需要添加更多字段的可能性。至少,这意味着您应该在某种类型的头中包含一个版本号,可以是文件本身,也可以是每个条目。更好的方法是标记各个字段(以允许可选属性),例如:
name: user1
address: 1600 pennsylvania ave
favorite color: blue
name: user2
address: 1 infinite loop
last login: 12th of never
你是对的:当你现在这样做的时候,没有办法读回内容,因为你不知道一个字符串从哪里结束,下一个字符串从哪里开始 您为避免对结构化数据使用fwrite()而引用的建议是好的,但将该建议解释为意味着您应该分别对每个元素使用fwrite()可能不是最好的解决方案 <>我想你应该考虑为你的文件使用不同的格式,而不是用FrEWE()写原始值。(例如,您的文件将无法移植到具有不同字节顺序的计算机。) 由于您的大多数元素看起来都是字符串和整数,您是否考虑过使用fprintf()进行写入,使用fscanf()进行读取的基于文本的格式?基于文本的格式而不是特定于应用程序的二进制格式的一大优点是,您可以使用标准工具(用于调试等)查看它
此外,无论您选择何种格式,请确保您考虑将来可能需要添加更多字段的可能性。至少,这意味着您应该在某种类型的头中包含一个版本号,可以是文件本身,也可以是每个条目。更好的方法是标记各个字段(以允许可选属性),例如:
name: user1
address: 1600 pennsylvania ave
favorite color: blue
name: user2
address: 1 infinite loop
last login: 12th of never
如果您的程序需要完全可移植,那么您不应该将int和short作为内存块写入磁盘:当您尝试在具有不同字号(例如32位->64位)或不同字节顺序的计算机上读取它们时,数据将被损坏 对于字符串,可以先写入长度,也可以在末尾包含终止符 最好的方法通常是使用基于文本的格式。例如,您可以将每条记录作为单独的行写入,字段由制表符或冒号分隔。(作为奖励,您不再需要在文件开头写入记录数——只需在到达文件末尾之前读取记录即可。) 编辑:但如果这是给你的课堂作业,你可能不需要担心可移植性。将
'\0'
终止符从字符串写入磁盘以对其进行分隔。