Как писать и читать динамические массивы из двоичного файла - PullRequest
0 голосов
/ 05 июля 2018

У меня есть эта структура

    struct _recipe
{
    char name[50];
    char** ingredients;
    char diff[12];
    int time;
    int calories;
    char** procedure;   
} recipe;

И я хочу скопировать все данные в двоичном файле. Прежде всего, я выделил динамически память как для ингредиентов, так и для процедуры, и я написал все, что мне нужно. Но тогда мне нужно записать все в двоичный файл. Я знаю, что они оба указатели, так что это означает, что если я использую

fwrite(&recipe,sizeof(recipe),1,fbr);

Я напишу в файле адрес, а не фактическое значение, которое мне нужно. Я попытался написать каждое поле структуры внутри файла таким образом

    fwrite(recipe.name,sizeof(recipe.name),1,fbr);

    fgets(recipe.ingredients[j],30,stdin);
            strcpy(buff,recipe.ingredients[j]);
            len = strlen(buff);
            fwrite(buff,sizeof(recipe.ingredients[0]),len,fbr);

   fwrite(recipe.diff,sizeof(recipe.diff),1,fbr);
   fwrite(&recipe.time,sizeof(recipe.time),1,fbr);
   fwrite(&recipe.calories,sizeof(recipe.calories),1,fbr);

    fgets(recipe.procedure[i],1000,stdin);
            strcpy(buff,recipe.procedure[i]);
            len = strlen(buff);
            fwrite(buff,sizeof(recipe.procedure[0]),len,fbr);

Я не уверен, что это правильный путь, но я попытался поместить строку внутрь другой и затем скопировать ее в файл. Проблема в том, что я не уверен, что это сработало, потому что я не знаю, какую команду я должен поставить для чтения всех значений, которые я сохранил. С названием, конечно, это работало, у меня не было проблем с этим, но потом, когда я собирался прочитать ингредиенты, я заблокировал себя, потому что я записал значение внутри другой строки, и я не знаю, какую длину я должен вставить в чтение. Может быть, я что-то упускаю, возможно, я вначале бездельничаю, когда пишу, но я не знаю, что делать в этот момент.

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Вы можете создать простое хранилище protocol для записи / чтения.

Например:

| struct recipe | t l v | t l v | ... | t l v | struct recipe | t l v | ... | t l v |

|<-      a complete struct recipe data      ->|


| description | t(ype) | l(ength) | v(alue)|
| ingredient  | i      | strlen() | string |
| procedure   | p      | strlen() | string |
| data end    | e      | 0        | <null> |

Прочтите данные рецепта:

1. Read a struct recipe.
2. Read a t, t=='i' -- go (3.), t=='p' -- go (4.), t=='e' -- go (5.).
3. Read a l, then read a string whose length is l as an ingredient. Go (2.).
4. Read a l, then read a string whose length is l as a procedure. Go (2.).
5. Finish.

Написать данные рецепта:

1. Write a struct recipe.
2. Write ingredients to `i strlen(ingredient) ingredient` one by one.
3. Write procedures to `p strlen(procedure) procedure` one by one.
4. Write `e 0`.
5. Finish.

Псевдокод: (просто демо, пожалуйста, создайте свой собственный protol-)

void write_recipe(recipe *r, FILE *fp)
{
    fwrite(r, sizeof(recipe), 1, fp);
    // ...
    for ()
    {
        sprintf(buff, "i %5d %s", strlen(r->ingredients[i]), r->ingredients[i]);
        fwrite(buff, strlen(buff), 1, fp);
    }
    sprintf(buff, "e 0");
    fwrite(buff, strlen(buff), 1, fp);
    //...
    for ()
    {
        sprintf(buff, "p %5d %s", strlen(r->procedure[i]), r->procedure[i]);
        fwrite(buff, strlen(buff), 1, fp);
    }
    sprintf(buff, "e 0");
    fwrite(buff, strlen(buff), 1, fp);
    // ...
}

void read_recipe(FILE *r, FILE *fp)
{
    fread(r, sizeof(recipe), 1, fp);
    // ...
    while (true)
    {
        fread(&t, sizeof(char), 1, fp);
        if (t == 'e')
        {
            // ...
            break;
        }
        fread(buff, sizeof(char), 7, fp);
        sscanf("%d", &len);
        fread(buff, sizeof(char), len, fp);
        buff[len] = 0;

        ingredient = malloc(sizeof(char) * (len + 1));
        strcpy(ingredient, buff);
        // ...
    }
    // ...
    while (true)
    {
        fread(&t, sizeof(char), 1, fp);
        if (t == 'e')
        {
            // ...
            break;
        }
        fread(buff, sizeof(char), 7, fp);
        sscanf("%d", &len);
        fread(buff, sizeof(char), len, fp);
        buff[len] = 0;

        procedure = malloc(sizeof(char) * (len + 1));
        strcpy(procedure, buff);
        // ...
    }
    // ...
}
0 голосов
/ 05 июля 2018

Вы хотите сделать что-то подобное, чтобы записать свой рецепт:

    fwrite(recipe.name,sizeof(recipe.name),1,fbr);
    for (int i = 0; i < num_ingredients; i++) {
            int len = strlen(recipe.ingredients[i]) + 1;
            int num_elements = fwrite(recipe.ingredients[i],sizeof(char),len,fbr);
            printf("wrote %d elements for %s\n", num_elements, recipe.ingredients[i]);
    }
    fwrite(recipe.diff,sizeof(recipe.diff),1,fbr);
    for (int i = 0; i < num_procedures; i++) {
            int len = strlen(recipe.procedure[i]) + 1;
            int num_elements = fwrite(recipe.procedure[i],sizeof(char),len,fbr);
            printf("wrote %d elements for %s\n", num_elements, recipe.procedure[i]);
    }

Вы также должны записать калории и время, конечно. Я также сделал бы это перед чтением чего-либо в структуру:

memset(&recipe, 0, sizeof(struct _recipe));

Если вы используете fprintf для записи калорий и времени с \n для разделителя, ваш файл рецепта будет выглядеть так:

$ od -c recipe.bin
0000000   m   u   f   f   i   n   s  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
0000060  \0  \0   f   l   o   u   r  \0   s   u   g   a   r  \0   e   g
0000100   g   s  \0   v   a   n   i   l   l   a  \0   n   u   t   s  \0
0000120   n   o       d   i   f   f  \0  \0  \0  \0  \0   m   i   x  \0
0000140   b   a   k   e  \0   r   e   s   t  \0   6   0  \n   2   5   0
0000160  \n
...