【问题标题】:How to read structures from a file into an array, modify it and write it back?如何将文件中的结构读取到数组中,对其进行修改并将其写回?
【发布时间】:2020-04-12 12:20:10
【问题描述】:

我希望标题是正确的,我无法更好地描述它,对不起。我有一个带有在程序“会话”期间传播的指针的结构。当然,每次都会抛出这个结构,所以我想将当前状态保存到二进制文件中。因为 entry:data 是指向未知长度数组的指针,所以我尝试将长度附加到每个条目。到目前为止一切正常,但是当我想删除或附加一个antry时,我遇到了问题。我想创建一个长度在文件头中的(结构条目)数组,但是一旦我创建了结构,该函数就不再起作用了。

这是一个最小的工作示例

#include <stdio.h>
#include <string.h>

struct header {
    int id;
    int len;
};

struct entry {
    int id;       
    int len; // length of data        
    char *data;   
};

void createNewStorage() {

    FILE *f = fopen("test.bin", "wb");   

    // create a header with id=1 and len=2 
    struct header hdr = {1, 2};
    fwrite(&hdr, sizeof(struct header), 1, f);

    char *data;

    data = "This is some data of unknown length, i hope it works";
    int id = 1;
    int len = strlen(data);    
    struct entry e = {id, len, data};
    fwrite(&e.id, sizeof(int), 1, f);
    fwrite(&e.len, sizeof(int), 1, f);
    fwrite(e.data, sizeof(char), strlen(e.data), f);

    id = 2; 
    data = "\x01\x12\x23"; 
    len = strlen(data); 
    e.id = id;
    e.data = data;
    e.len = len;
    fwrite(&e.id, sizeof(int), 1, f);
    fwrite(&e.len, sizeof(int), 1, f);
    fwrite(e.data, sizeof(char), e.len, f);

    fclose(f);

}

void appendNewEntry() {

    FILE *f = fopen("test.bin", "rb");       

    // get the header
    struct header hdr;
    fread(&hdr.id, sizeof(int), 1, f);
    fread(&hdr.len, sizeof(int), 1, f);
    printf("hdr: id='%d', len='%d'\n", hdr.id, hdr.len);

    // get the entries
    int id, len = 0; char *data; 
    int i = 0;
    while(i < hdr.len) {    
        fread(&id, sizeof(int), 1, f);
        fread(&len, sizeof(int), 1, f);
        fread(&data, sizeof(char), len, f);
        printf("entry: id='%d', len='%d', data='%s'\n", id, len, &data);
        i++;        
    }    
    printf("Done..\n");
    fclose(f);

}

int main(void){
    createNewStorage();
    appendNewEntry();
    return 0;
}

提前谢谢你。

编辑:我终于搞定了,这是最终代码。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct header {
    int id;
    int len;
};

struct entry {
    int id;       
    int len; // length of data        
    char *data;   
};

void create() {
    FILE *f = fopen("test.bin", "wb");   
    // create a header with id=1 and len=2 
    struct header hdr = {1, 2};
    fwrite(&hdr, sizeof(struct header), 1, f);
    char *data;
    data = "This is some data of unknown length, i hope it works";
    int id = 1;
    int len = strlen(data);    
    struct entry e = {id, len, data};
    fwrite(&e.id, sizeof(int), 1, f);
    fwrite(&e.len, sizeof(int), 1, f);
    fwrite(e.data, sizeof(char), strlen(e.data), f);
    id = 2; 
    data = "\x01\x12\x23"; 
    len = strlen(data); 
    e.id = id;
    e.data = data;
    e.len = len;
    fwrite(&e.id, sizeof(int), 1, f);
    fwrite(&e.len, sizeof(int), 1, f);
    fwrite(e.data, sizeof(char), e.len, f);
    fclose(f);
}

void modify() {
    FILE *f = fopen("test.bin", "rb");       
    // get the header
    struct header hdr;
    fread(&hdr.id, sizeof(int), 1, f);
    fread(&hdr.len, sizeof(int), 1, f);
    printf("Reading storage hdr: id='%d', len='%d' ", hdr.id, hdr.len);
    // create a new list to store all existing entries
    struct entry list[hdr.len];    
    // get the entries
    int id, len = 0; char *data; 
    int i = 0;
    while(i < hdr.len) {    
        fread(&id, sizeof(int), 1, f);
        fread(&len, sizeof(int), 1, f);
        data = malloc((len + 1) * sizeof(char));
        fread(data, sizeof(char), len, f);
        data[len] = '\0';
        //printf("entry: id='%d', len='%d', data='%s'\n", id, len, &data[0]);
        struct entry e = {id, len, data};
        list[i] = e;
        i++;        
    }    
    printf("Done..\n");
    printf("The list has %d entries\n", i);
    int il = 0;
    while(il < i) {
        printf("entry %d: len='%d', data='%s'\n", il, list[il].len, list[il].data);
        il++;
    }    
    fclose(f);
}

void append(char *newdata) {
    printf("Appending new data..\n");
    FILE *f = fopen("test.bin", "rb");       
    // get the header
    struct header hdr;
    fread(&hdr.id, sizeof(int), 1, f);
    fread(&hdr.len, sizeof(int), 1, f);
    printf("Reading storage hdr: id='%d', len='%d' ", hdr.id, hdr.len);
    // create a new list to store all existing entries
    struct entry list[hdr.len];    
    // get the entries
    int id, len = 0; char *data; 
    int i = 0;
    while(i < hdr.len) {    
        fread(&id, sizeof(int), 1, f);
        fread(&len, sizeof(int), 1, f);
        data = malloc((len + 1) * sizeof(char));
        fread(data, sizeof(char), len, f);
        data[len] = '\0';
        //printf("entry: id='%d', len='%d', data='%s'\n", id, len, &data[0]);
        struct entry e = {id, len, data};
        list[i] = e;
        i++;        
    }    
    printf("Done..\n");
    /*
    printf("The list has %d entries\n", i);
    int il = 0;
    while(il < i) {
        printf("entry %d: len='%d', data='%s'\n", il, list[il].len, list[il].data);
        il++;
    }
    */
    fclose(f);    
    f = fopen("test.bin", "wb");    
    struct header outhdr = {hdr.id, hdr.len+1};
    fwrite(&outhdr, sizeof(struct header), 1, f);    
    int il = 0;
    while(il < i) {
        printf("writing entry %d\n", il, list[il].len, list[il].data);
        fwrite(&list[il].id, sizeof(int), 1, f);
        fwrite(&list[il].len, sizeof(int), 1, f);
        fwrite(&list[il].data[0], sizeof(char), list[il].len, f);
        il++;
    }
    il++;
    struct entry e;
    int nid = il;  
    int nlen = strlen(newdata); 
    e.id = nid;
    e.data = newdata;
    e.len = nlen;
    printf("writing new entry\n");
    fwrite(&e.id, sizeof(int), 1, f);
    fwrite(&e.len, sizeof(int), 1, f);
    fwrite(e.data, sizeof(char), e.len, f);        
    fclose(f);    
}

void erase(int entryId) {
    printf("Appending new data..\n");
    FILE *f = fopen("test.bin", "rb");       
    // get the header
    struct header hdr;
    fread(&hdr.id, sizeof(int), 1, f);
    fread(&hdr.len, sizeof(int), 1, f);
    printf("Reading storage hdr: id='%d', len='%d' ", hdr.id, hdr.len);
    // create a new list to store all existing entries
    struct entry list[hdr.len];    
    // get the entries
    int id, len = 0; char *data; 
    int i = 0;
    while(i < hdr.len) {    
        fread(&id, sizeof(int), 1, f);
        fread(&len, sizeof(int), 1, f);
        data = malloc((len + 1) * sizeof(char));
        fread(data, sizeof(char), len, f);
        data[len] = '\0';
        //printf("entry: id='%d', len='%d', data='%s'\n", id, len, &data[0]);
        struct entry e = {id, len, data};
        list[i] = e;
        i++;        
    }    
    printf("Done..\n");
    /*
    printf("The list has %d entries\n", i);
    int il = 0;
    while(il < i) {
        printf("entry %d: len='%d', data='%s'\n", il, list[il].len, list[il].data);
        il++;
    }
    */
    fclose(f);
    f = fopen("test.bin", "wb");    
    struct header outhdr = {hdr.id, hdr.len-1};
    fwrite(&outhdr, sizeof(struct header), 1, f);    
    int il = 0;
    while(il < i) {
        if(list[il].id == entryId) {
            // this is the one to delete
            //printf("THIS IS IT -> %d\n", il);
        } else {
            printf("writing entry %d\n", il, list[il].len, list[il].data);
            fwrite(&list[il].id, sizeof(int), 1, f);
            fwrite(&list[il].len, sizeof(int), 1, f);
            fwrite(&list[il].data[0], sizeof(char), list[il].len, f);
        }
        il++;
    }       
}

int main(void){

    create();

    getch();

    char *input;
    input = "Mein Hund ist der aller aller Beste";
    append(input);

    getch();

    erase(1);

    return 0;
}

【问题讨论】:

  • 您能否更详细地描述一下“不起作用”对您的程序意味着什么?预期结果和实际结果是什么?
  • '不起作用'意味着它只是停止了。你试过重现它吗?对你起作用吗?在我的电脑上,光标图标弹出加载光标,然后控制台崩溃。真的,我无话可说。
  • 您没有提供minimal verifiable example,因此很难尝试。请这样做。
  • 在调试器中运行它,它可以立即指出问题所在:fread(&amp;data[0], sizeof(char), len, f); 它在该行出现问题。这给你任何线索吗?
  • 在继续之前,请使用gcc -Wall -Werror -o program program.c 编译您的代码,并将program 替换为您的实际文件名。这将显示大多数警告并将警告视为错误。也就是说,在修复导致警告的代码之前,您将无法运行代码。

标签: c struct


【解决方案1】:

试试这个:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct header {
    int id;
    int len;
};

struct entry {
    int id;
    int len; // length of data
    char *data;
};

void createNewStorage() {

    FILE *f = fopen("test.bin", "wb");

    // create a header with id=1 and len=2
    struct header hdr = {1, 2};
    fwrite(&hdr, sizeof(struct header), 1, f);

    char *data;

    data = "This is some data of unknown length, i hope it works";
    int id = 1;
    int len = strlen(data);
    struct entry e = {id, len, data};
    fwrite(&e.id, sizeof(int), 1, f);
    fwrite(&e.len, sizeof(int), 1, f);
    fwrite(e.data, sizeof(char), strlen(e.data), f);

    id = 2;
    data = "\x01\x12\x23";
    len = strlen(data);
    e.id = id;
    e.data = data;
    e.len = len;
    fwrite(&e.id, sizeof(int), 1, f);
    fwrite(&e.len, sizeof(int), 1, f);
    fwrite(e.data, sizeof(char), e.len, f);

    fclose(f);

}

void appendNewEntry() {

    FILE *f = fopen("test.bin", "rb");

    // get the header
    struct header hdr;
    fread(&hdr.id, sizeof(int), 1, f);
    fread(&hdr.len, sizeof(int), 1, f);
    printf("hdr: id='%d', len='%d'\n", hdr.id, hdr.len);

    // get the entries
    int id, len = 0; char *data;
    int i = 0;
    while(i < hdr.len) {
        fread(&id, sizeof(int), 1, f);
        fread(&len, sizeof(int), 1, f);
        data = malloc((len + 1) * sizeof(char));
        fread(data, sizeof(char), len, f);
        data[len] = '\0';
        printf("entry: id='%d', len='%d', data='%s'\n", id, len, data);
        i++;
    }
    printf("Done..\n");
    fclose(f);

}

int main(void){
    createNewStorage();
    appendNewEntry();
    return 0;
}

输出

hdr: id='1', len='2'
entry: id='1', len='52', data='This is some data of unknown length, i hope it works'
entry: id='2', len='3', data='#'
Done..

注意

我必须添加#inlude &lt;stdlib.h&gt; 才能使用malloc。原始代码在freadprintf 中不必要地使用了&amp;data。另外,看起来数据实际上并没有被读入entry的列表,这看起来很奇怪。

警告

此代码分配内存,用户有责任在程序结束前释放内存。

【讨论】:

  • 在继续之前,请使用 gcc -Wall -Werror 编译您的代码。有什么错误吗?尝试将“&data”替换为“&data[0]”。
  • @phpnoob 我有你的代码版本,可以运行并打印出数据。看看吧。
  • 很好,非常感谢!对不起我的不耐烦。在 SO 上询问变得越来越难。我已经编辑了我的问题,请查看我的最终代码,包括附加和删除功能。 ps:我希望你知道我的第一条评论是个坏笑话:P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-13
  • 2017-06-25
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多