首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >读写内存中的数据

读写内存中的数据
EN

Stack Overflow用户
提问于 2021-02-17 12:48:47
回答 1查看 47关注 0票数 2

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

代码语言:javascript
运行
复制
#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);

}

但是请注意,这些都是堆栈上的值,不涉及指针/间接地址。例如,当可能涉及多个指针,多个变量可能指向相同的内存位置等时,如何将数据序列化到文件中。这是协议缓冲区有效执行的操作吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-17 13:10:15

好的,所以你想要一个二进制文件。很久以前我就是这样做的。这很好。当你移动到另一个平台或bitness时,它就会崩溃。我在用老方法教学,因为这是一个很好的起点。更新的方式现在很受欢迎,因为它们在改变平台或比特时仍然有效。

在将记录写入文件时,我会使用这样的结构:

代码语言:javascript
运行
复制
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;

查看Owner结构如何具有Id成员。这些只是其他结构数组的索引。

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

作者看起来像这样:

代码语言:javascript
运行
复制
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);
}

阅读器依次看起来是这样的:

代码语言:javascript
运行
复制
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中并将其写回即可。最终,您将学习数据库,它将为您处理这些内容。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66235920

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档