Запись структуры, содержащей строку, в двоичный файл - PullRequest
3 голосов
/ 30 июня 2011

У меня есть двоичный файл, в котором я записываю смещение, при котором происходит запись в другие файлы, и данные, которые записываются с этим смещением. Теперь я определяю структуру каждой записи в журнале как

struct log_record{
                    int offset;
                    char *data;
               }
struct log_record t;

Когда я записываю запись в файл, у меня есть длина данных, которые я записываю в файл, и, следовательно, перед назначением я выделяю пространство как

t.data = (char*)malloc(sizeof(char)*strlen(buff));/*buf holds the data to be written*/

Теперь у меня есть длина записи, которую я записываю в файл ... Но проблема во время чтения. Как мне выделить пространство для структуры, в которую я записываю запись и во фреде, каким должен быть размер записи. Я несколько смущен. Буду благодарен за помощь

Ответы [ 3 ]

3 голосов
/ 30 июня 2011

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

В вашем конкретном случае вместо написания struct log_record вы хотите написать три вещи:

  • offset (выберите свой размер и порядок следования байтов и придерживайтесь его).
  • Длина data (в том же формате, что и выше).
  • Фактическийбайты data.

Затем, когда вы читаете данные обратно, читайте в offset и переставляйте его байты в соответствии с локальным порядком байтов.Затем прочитайте длину (так же, как offset).Теперь вы знаете, насколько велик data, чтобы вы могли выделить свою память и отбросить ее с диска с помощью одного вызова fread.

О, и не приводить возвращаемое значение malloc, в этом нет необходимости, и это может скрыть проблемы.Вместо этого просто скажите это:

/* See above for how to figure out data_length. */
t.data = malloc(sizeof(char) * data_length);
3 голосов
/ 30 июня 2011

Вам необходимо записать длину строки, так как длина строки является переменной.

Обратите внимание, что strlen() не возвращает размер, включая завершающий NULL.

РЕДАКТИРОВАТЬ + РЕДАКТИРОВАТЬ 2 (благодаря му слишком короткий) + РЕДАКТИРОВАТЬ 3 (благодаря му слишком короткий)

Вот как бы я это сделал:

t.data = (char*) malloc(sizeof(char) * strlen(buff) + 1);
strcpy(t.data, buff);

// ...
int data_size = strlen(t.data) + 1;
fwrite(&t.offset,  1, sizeof(t.offset),   file);
fwrite(&data_size, 1, sizeof(data_size),  file);
fwrite(t.data,     1, strlen(t.data) + 1, file);
0 голосов
/ 30 июня 2011

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

Поскольку у меня не было ничего лучше, я написал небольшую программу, которая, я надеюсь, сделает то, что вы ищете.Нет проверки ошибок:)

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

typedef struct {
    int offset;
    int length;
    char *data;
} log_record;

void write_to_file(const char *filename)
{
    log_record lr;
    const int num_records = 10;
    char buf[100];
    int i;
    FILE *fp;

    fp = fopen(filename, "wb");

    for(i = 0; i < num_records; ++i)
    {
        sprintf(buf, "Data entry %d goes here. Beware of size limit!", i);
        lr.length = strlen(buf) + 1;
        lr.offset = i;
        lr.data = malloc(sizeof(char) * lr.length);
        strncpy(lr.data, buf, lr.length);   
        fwrite(&lr.offset, sizeof(lr.offset), 1, fp);
        fwrite(&lr.length, sizeof(lr.length), 1, fp);
        fwrite(lr.data, sizeof(char), lr.length, fp);   
        free(lr.data);
    }   
    fclose(fp); 
}

void read_from_file(const char * filename)
{
    log_record lr;
    int tmp;
    FILE *fp;

    fp = fopen(filename, "rb");

    while (feof(fp) == 0) 
    {
        tmp = fgetc(fp);
        if(tmp != EOF)
        {
            ungetc(tmp, fp);            
            fread(&lr.offset, sizeof(int), 1, fp);
            fread(&lr.length, sizeof(int), 1, fp);
            lr.data = malloc(sizeof(char) * lr.length);
            fread(lr.data, sizeof(char), lr.length, fp);
            free(lr.data);      
        }
    }
    fclose(fp); 
}


int main(int argc, char *argv[])
{
    write_to_file("temp.bin");  
    read_from_file("temp.bin"); 
    return 0;
}
...