C 在存储器中读写数据

C 在存储器中读写数据,c,protocol-buffers,C,Protocol Buffers,在下面的示例中,我将获取一个在内存中占用32字节的结构,并将其写入一个文件,然后将其读回——即,将数据序列化为二进制格式: #include <stdio.h> typedef struct _Person { char name[20]; int age; double weight; } Person; int main(void) { Person tom = (Person) {.name="Tom", .a

在下面的示例中,我将获取一个在内存中占用32字节的结构,并将其写入一个文件,然后将其读回——即,将数据序列化为二进制格式:

#include <stdio.h>

typedef struct _Person {
    char   name[20];
    int    age;
    double weight;
} Person;

int main(void)
{

    Person tom = (Person) {.name="Tom", .age=20, .weight=125.0};

    // write the struct to a binary file
    FILE *fout = fopen("person.b", "wb");
    fwrite(&tom, sizeof tom, 1, fout);
    fclose(fout);

    // read the binary data and set the person to that
    Person unknown;
    FILE *fin = fopen("person.b", "rb");
    fread(&unknown, sizeof unknown, 1, fin);
    fclose(fin);

    // confirm all looks ok
    printf("{name=%s, age=%d, weight=%f}", unknown.name, unknown.age, unknown.weight);

}
#包括
类型定义结构人{
字符名[20];
智力年龄;
双倍重量;
}人;
内部主(空)
{
人汤姆=(人){.name=“汤姆”,.age=20,.weight=125.0};
//将结构写入二进制文件
文件*fout=fopen(“person.b”、“wb”);
fwrite(&tom,tom的大小,1,fout);
fclose(fout);
//读取二进制数据并将人员设置为该值
身份不明者;
文件*fin=fopen(“person.b”、“rb”);
fread(未知,尺寸未知,1,fin);
财务总监(财务);
//确认一切正常
printf(“{name=%s,age=%d,weight=%f}”,unknown.name,unknown.age,unknown.weight);
}

但是请注意,这些都是堆栈上的值,不涉及指针/间接寻址。例如,当涉及多个指针、多个变量可能指向同一内存位置等时,数据如何序列化到文件中。协议缓冲区就是这样做的吗?

确定,因此您需要一个二进制文件。很久以前我就这样做了。很好。当你移动到另一个平台或bitness时,它就会断开。我用老方法教学,因为这是一个很好的起点。更新的方法现在很流行,因为它们在改变平台或比特数时仍然有效

将记录写入文件时,我会使用如下结构:

typedef struct _Person {
    char   name[20];
    int    age;
    double weight;
} Person;

typedef struct _Thing {
    char name[20];
};

typedef struct _Owner {
    int personId;
    int thingId;
} Owner;
void writeall(FILE *h, Person *allPeople, int nPeople, Thing *allThings, int nThings, Owner *allOwners, int nOwners)
{
    // Error checking omitted for brevity
    fwrite(&nPeople, sizeof(nPeople), 1, h);
    fwrite(allPeople, sizeof(*allPeople), nPeople, h);
    fwrite(&nThings, sizeof(nThings), 1, h);
    fwrite(allThings, sizeof(*allThings), nThings, h);
    fwrite(&nOwners, sizeof(nOwners), 1, h);
    fwrite(allOwners, sizeof(*allOwners), nOwners, h);
}
int writeall(FILE *h, Person **allPeople, int *nPeople, int *aPeople, Thing **allThings, int *nThings, int *aThings, Owner **allOwners, int *nOwners, int *aOwners)
{
    *aPeople = 0; // Don't crash on bad read
    *aThigns = 0;
    *aOwners = 0;
    *allPeople = NULL;
    *allThings = NULL;
    *allOwners = NULL;

    if (1 != fread(nPeople, sizeof(*nPeople), 1, h)) return 0;
    *allPeople = malloc(sizeof(**allPeople) * *nPeople);
    if (!allPeople) return 0; // OOM
    *aPeople = *nPeople;
    if (*nPeople != fread(*allPeople, sizeof(**allPeople), nPeople, h)) return 0;

    if (1 != fread(nThings, sizeof(*nThings), 1, h)) return 0;
    *allThings = malloc(sizeof(**allThings) * *nThings);
    if (!allThings) return 0; // OOM
    *aThings = *nThings;
    if (*nThings != fread(*allThings, sizeof(**allThings), nThings, h)) return 0;

    if (1 != fread(nOwners, sizeof(*nOwners), 1, h)) return 0;
    *allOwners = malloc(sizeof(**allOwners) * *nOwners);
    if (!allOwners) return 0; // OOM
    *aOwners = *nOwners;
    if (*nOwners != fread(*allOwners, sizeof(**allOwners), nOwners, h)) return 0;

    return 1;
}
查看
所有者
结构如何具有Id成员。这些只是其他结构数组的索引

它们可以一个接一个地写入文件,通常以一个直接写入的整数作为前缀,表示每种记录的数量。读取器只是分配一个结构数组,其
malloc
大到足以容纳它们。当我们在内存中添加更多项时,我们使用
realloc
调整数组的大小。我们还可以(也应该)标记删除(比如将name的第一个字符设置为0)并在以后重用该记录

作者看起来像这样:

typedef struct _Person {
    char   name[20];
    int    age;
    double weight;
} Person;

typedef struct _Thing {
    char name[20];
};

typedef struct _Owner {
    int personId;
    int thingId;
} Owner;
void writeall(FILE *h, Person *allPeople, int nPeople, Thing *allThings, int nThings, Owner *allOwners, int nOwners)
{
    // Error checking omitted for brevity
    fwrite(&nPeople, sizeof(nPeople), 1, h);
    fwrite(allPeople, sizeof(*allPeople), nPeople, h);
    fwrite(&nThings, sizeof(nThings), 1, h);
    fwrite(allThings, sizeof(*allThings), nThings, h);
    fwrite(&nOwners, sizeof(nOwners), 1, h);
    fwrite(allOwners, sizeof(*allOwners), nOwners, h);
}
int writeall(FILE *h, Person **allPeople, int *nPeople, int *aPeople, Thing **allThings, int *nThings, int *aThings, Owner **allOwners, int *nOwners, int *aOwners)
{
    *aPeople = 0; // Don't crash on bad read
    *aThigns = 0;
    *aOwners = 0;
    *allPeople = NULL;
    *allThings = NULL;
    *allOwners = NULL;

    if (1 != fread(nPeople, sizeof(*nPeople), 1, h)) return 0;
    *allPeople = malloc(sizeof(**allPeople) * *nPeople);
    if (!allPeople) return 0; // OOM
    *aPeople = *nPeople;
    if (*nPeople != fread(*allPeople, sizeof(**allPeople), nPeople, h)) return 0;

    if (1 != fread(nThings, sizeof(*nThings), 1, h)) return 0;
    *allThings = malloc(sizeof(**allThings) * *nThings);
    if (!allThings) return 0; // OOM
    *aThings = *nThings;
    if (*nThings != fread(*allThings, sizeof(**allThings), nThings, h)) return 0;

    if (1 != fread(nOwners, sizeof(*nOwners), 1, h)) return 0;
    *allOwners = malloc(sizeof(**allOwners) * *nOwners);
    if (!allOwners) return 0; // OOM
    *aOwners = *nOwners;
    if (*nOwners != fread(*allOwners, sizeof(**allOwners), nOwners, h)) return 0;

    return 1;
}
读者又是这样看的:

typedef struct _Person {
    char   name[20];
    int    age;
    double weight;
} Person;

typedef struct _Thing {
    char name[20];
};

typedef struct _Owner {
    int personId;
    int thingId;
} Owner;
void writeall(FILE *h, Person *allPeople, int nPeople, Thing *allThings, int nThings, Owner *allOwners, int nOwners)
{
    // Error checking omitted for brevity
    fwrite(&nPeople, sizeof(nPeople), 1, h);
    fwrite(allPeople, sizeof(*allPeople), nPeople, h);
    fwrite(&nThings, sizeof(nThings), 1, h);
    fwrite(allThings, sizeof(*allThings), nThings, h);
    fwrite(&nOwners, sizeof(nOwners), 1, h);
    fwrite(allOwners, sizeof(*allOwners), nOwners, h);
}
int writeall(FILE *h, Person **allPeople, int *nPeople, int *aPeople, Thing **allThings, int *nThings, int *aThings, Owner **allOwners, int *nOwners, int *aOwners)
{
    *aPeople = 0; // Don't crash on bad read
    *aThigns = 0;
    *aOwners = 0;
    *allPeople = NULL;
    *allThings = NULL;
    *allOwners = NULL;

    if (1 != fread(nPeople, sizeof(*nPeople), 1, h)) return 0;
    *allPeople = malloc(sizeof(**allPeople) * *nPeople);
    if (!allPeople) return 0; // OOM
    *aPeople = *nPeople;
    if (*nPeople != fread(*allPeople, sizeof(**allPeople), nPeople, h)) return 0;

    if (1 != fread(nThings, sizeof(*nThings), 1, h)) return 0;
    *allThings = malloc(sizeof(**allThings) * *nThings);
    if (!allThings) return 0; // OOM
    *aThings = *nThings;
    if (*nThings != fread(*allThings, sizeof(**allThings), nThings, h)) return 0;

    if (1 != fread(nOwners, sizeof(*nOwners), 1, h)) return 0;
    *allOwners = malloc(sizeof(**allOwners) * *nOwners);
    if (!allOwners) return 0; // OOM
    *aOwners = *nOwners;
    if (*nOwners != fread(*allOwners, sizeof(**allOwners), nOwners, h)) return 0;

    return 1;
}
有一种古老的技术,可以将堆直接写入磁盘,然后再次读取。我建议永远不要使用它,也不要在磁盘上存储指针。这样做就是安全噩梦


当内存便宜时,我会讨论如何使用块分配和链接块来动态更新部分磁盘记录;但是现在,对于在这个级别将遇到的问题,我说不要麻烦,只要将整个内容读入RAM,然后再写出来。最终,您将学习数据库,它为您处理这些内容。

您需要使用序列化格式。现在流行的是JSON和XML。是的,这也是协议缓冲区的功能。@Barmar是的,我想保持它为二进制格式,所以可能是protobuf或类似的东西。@samuelbrody1249这可能会对你有帮助。。。不,您根本没有序列化。您正在将结构取出的字节数写入文件(包括任何填充字节)。虽然这可以在同一个编译器和同一台计算机上工作,但它是不可移植的,因为C标准没有指定填充字节的位置。这取决于各个编译器的实现。序列化意味着将结构的每一部分都写出来,这样无论您使用的是哪种编译器,也不管是否为endianness,都可以将其可移植地读回。