Сохранение структуры C с символом* представляет в виде строки в файл

Я пытаюсь сохранить структуру с символом* строка в файл.

struct d_object {
    int flags;
    int time;
    int offset;
    char *filename;
};

Проблема состоит в том, что при выполнении этого я очевидно только сохраню адрес того указателя, а не строки. Таким образом, то, что я сделал, является просто использованием символьный массив и но я вынужден установить максимальный размер строки. Это хорошо работает, однако я задавался вопросом, существует ли так или иначе хранения структуры с символом* (что я malloc в какой-то момент) в файле, и затем получите его. Я могу сохранить строку, и структура разделяют и затем получают их, но это - настоящая путаница. Было бы предпочтительно, если я мог бы загрузить и сохранить всю структуру (та выше) в файл.Спасибо!

Код с массивом символов ниже:

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

struct d_object {
    int flags;
    int time;
    int offset;
    char filename[255];
};

int main(int argc, char **argv) {

    struct d_object fcb;

    fcb.flags=5;
    fcb.time=100000;
    fcb.offset=220;
    strncpy(fcb.filename,"myfile",255);


    int fd=open("testfile",O_RDWR);
    write(fd,&fcb,sizeof(fcb));
    close(fd);


    int fd2 = open("testfile",O_RDONLY);
    struct d_object new_fcb; 
    read(fd2,&new_fcb,sizeof(new_fcb));

    printf("read from file testfile: %s\n",new_fcb.filename);

    return 0;

}

P.S.: я не использую Функции потока просто, потому что это на самом деле предназначено, чтобы быть выполненным на встроенной ОС, которая не имеет их. Я только что адаптировал код к *BSD/Linux, таким образом, он имеет больше смысла при задавании вопроса.

7
задан theprole 18 July 2010 в 09:47
поделиться

5 ответов

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

Вы можете преобразовать ваш код обратно в:

struct d_object {
    int flags;
    int time;
    int offset;
    char * filename;
};

А затем сохранить каждую часть данных отдельно:

write( fd, &record.flags, sizeof( int ) );
write( fd, &record.time, sizeof( int ) );
write( fd, &record.offset, sizeof( int ) );
int filename_length = strlen( filename );
write( fd, &filename_length, sizeof( int ) );
write( fd, record.filename, filename_length );

Для чтения, вам придется читать каждый элемент отдельно, а затем имя файла:

int filename_length;

read( fd, &emptyRecord.flags, sizeof( int ) );
read( fd, &emptyRecord.time, sizeof( int ) );
read( fd, &emptyRecord.offset, sizeof( int ) );

read( filename_length, sizeof( int ), 1, file );
emptyRecord.filename = (char *) malloc( sizeof( char ) * ( filename_length  +1) );
read( fd, emptyRecord.filename, filename_length );
*( emptyRecord.filename + filename_length ) = 0;
7
ответ дан 6 December 2019 в 15:17
поделиться

Сериализация никогда не бывает красивой. Как насчет хранения длины строки в указателе, и чтобы строка следовала за struct в файле? Что-то вроде этого (предупреждение, код скомпилирован мозгом):

void write_object(struct d_object *s, int fd) {
    struct d_object copy = *s;
    copy.filename = (char*)strlen(s->filename);
    write(fd, &copy, sizeof(copy));
    write(fd, s->filename, (size_t)copy.filename);
}

void read_object(struct d_object *s, int fd) {
    read(fd, s, sizeof(struct d_object));
    char *filename = malloc(((size_t)s->filename) + 1);
    read(fd, filename, (size_t)s->filename);
    filename[(size_t)s->filename] = '\0';
    s->filename = filename;
}
2
ответ дан 6 December 2019 в 15:17
поделиться

Теперь, когда я знаю природу вашей проблемы, почему бы не попробовать гибкие массивы? Вместо использования char * filename; используйте char filename [1] и malloc (sizeof struct d_object + filename_len) для размещения ваших структур. Добавьте элемент размера, и вы можете легко записать объект на диск с помощью одного вызова write и загрузить его с диска двумя вызовами (первый для чтения элемента размера, второй для чтения всего объекта после выделения Это).

Обратите внимание, что «официальный» способ создания гибких массивов в C99 - это [] , а не [1], но [1] гарантированно работает как следствие других требований стандарта и работает и на C89. [1] потратит впустую несколько байтов, поэтому, если ваш компилятор поддерживает [] , вы можете захотеть его использовать.

2
ответ дан 6 December 2019 в 15:17
поделиться

Ваша проблема здесь на самом деле является симптомом гораздо более серьезной проблемы: вы не должны читать / записывать двоичные структуры данных между памятью и файлами. Мало того, что нет четкого способа чтения / записи структур с указателями на другие данные (это относится не только к строкам, но и к вложенным данным, связанным спискам и т. Д.), Но и формат данных на диске будет зависеть от вашего хост-компьютера и C и не будет переноситься в другие среды.

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

Если ваши данные являются иерархическими, вам могут подойти JSON, XML или EBML. Если это достаточно простые текстовые файлы или бинарный формат доморощенного языка (записанный побайтово, чтобы его можно было переносить), могут подойти.

Поскольку вы, кажется, не знакомы с этими проблемами, возможно, стоит написать код для загрузки / сохранения нескольких простых форматов двоичных файлов (например, .tga или .wav) в качестве упражнения, прежде чем пытаться создать что-то для своего собственные данные.

2
ответ дан 6 December 2019 в 15:17
поделиться

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

Что вам нужно сделать, так это написать пару функций для преобразования ваших данных в доступную для записи форму и считывания их обратно из файла. Это называется «сериализацией» / «десериализацией» на языках, которые вызывают больше беспокойства по этому поводу.

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

Когда вы снова прочитаете это, вы захотите malloc / calloc себе кусок памяти для хранения символьных данных; если вы сохранили размер, вы будете знать, насколько большим нужно сделать этот malloc. Прочтите двоичные данные в структуру, прочтите данные char в память malloc, сохраните указатель на блок malloc в структуре, и вы воссоздадите оригинал.

Никакой магии. Просто данные и немного смазки для локтей.

РЕДАКТИРОВАТЬ

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

1
ответ дан 6 December 2019 в 15:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: