使用fwrite/fread和数据结构的几个问题

Ric*_*ral 1 c file-io fwrite fread data-structures

我正在使用fwrite()并且fread()第一次将一些数据结构写入磁盘,我对最佳实践和正确的处理方式有几个问题.

我正在写入磁盘(所以我以后可以读回来)是在Graph结构中插入的所有用户配置文件.每个图形顶点都是以下类型:

typedef struct sUserProfile {
    char name[NAME_SZ];
    char address[ADDRESS_SZ];
    int socialNumber;
    char password[PASSWORD_SZ];

    HashTable *mailbox;
    short msgCount;
} UserProfile;
Run Code Online (Sandbox Code Playgroud)

这就是我目前正在将所有配置文件写入磁盘的方式:

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);
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • fwrite()您看到的第一个将写入图表中的总用户数,因此我知道需要读回多少数据.
  • break是为了测试目的.有成千上万的用户,我还在试验代码.

我的问题:

  • 看完这个,我决定使用fwrite(),而不是每个元素写入整个结构.我也避免将指针写入邮箱,因为我不需要保存该指针.那么,这是要走的路吗?fwrite()对于整个结构,多个而不是全局的?这不慢吗?
  • 我该如何回读这些内容?我知道我必须使用,fread()但我不知道字符串的大小,因为我曾经strlen()写过它们.我可以strlen()在写字符串之前写出输出,但有没有更好的方法没有额外的写入?

dav*_*420 5

如果您的程序需要完全可移植,那么您不应该将内存和短路写入磁盘作为内存块:当您尝试在具有不同字长的计算机上读取数据时,数据将被破坏(例如32位 - > 64位)或不同的字节顺序.

对于字符串,您可以先写入长度,也可以在末尾包含终止符.

最好的方法通常是使用基于文本的格式.例如,您可以将每个记录编写为单独的行,其中的字段由制表符或冒号分隔.(作为奖励,您不再需要在文件开头写入记录数量的计数---只需读入记录,直到您到达文件末尾.)

编辑:但如果这是一个你已经给出的课程作业,你可能不需要担心可移植性.'\0'将字符串中的终止符写入磁盘以分隔它们.读取它时不要担心效率,最慢的位是磁盘访问.

或者甚至fwrite()整个结构fread()都重新进入.担心指针?在读取它时用一个安全值覆盖它.不要担心磁盘上浪费的空间(除非你被要求最小化磁盘使用).

如果你确实需要以便携式二进制格式将非负的int写入磁盘,你可以这样做:

  • 第一个字节是后续字节数
  • 第二个字节是int中最重要的非零字节
  • ...
  • 最后一个字节是int中最不重要的字节

所以:

  • 0编码为00
  • 1编码为01 01
  • 2编码为01 02
  • 255 - > 01 ff
  • 256 - > 02 01 00
  • 65535 - > 02 ff ff
  • 65536 - > 03 01 00 00
  • 等等

如果您还需要对负数进行编码,则需要在某处为符号保留一点.