Как читать и записывать много объектов (или любых данных) в буфер?

Я пишу программу для сохранения некоторого объекта (структуры) в буфер. У меня нет эксперимента, чтобы записать много объектов в буфер и прочитать эти объекты из буфера. Любая помощь будет оценена.
Мой код может записать один элемент в объект, и я хочу записать много объектов в буфер

struct PointFull {
double lat;
double lon;
};

PointFull item1;
PointFull item2;
PointFull item3;
PointFull item4;
PointFull item5;

void* buffer = malloc(sizeof (PointFull));
int fd = open("output", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);
if (fd < 0) {
printf("Error opening file\n");
return 1;
}

//The below function can write only one item to buffer. How to write 5 item (from item1 to item5) to the buffer
//memcpy(buffer, &item1, sizeof (item));

write(fd, buffer, sizeof (item));

Теперь у меня есть файл с именем «output» на жестком диске, а затем я хочу прочитать файл для проверки данных.

    int fd2 = open("output", O_RDONLY, S_IWUSR | S_IRUSR);
if (fd2 < 0) {
printf("Error opening file\n");
return 1;
}
void* bufferRead;
bufferRead = malloc(5* sizeof (PointFull));
read(fd2, bufferRead,sizeof (PointFull));

На данный момент у меня есть bufferRead, содержащий 5 элементов, но я не знаю, как читать буфер для вставки данных в структуру ??? Пожалуйста, помогите мне!

2

Решение

Ну, что вы хотите сделать, это сериализация. Скажем, у вас есть такая структура:

struct PointFull {
int lat;
int lon;
};

а также

PointFull item1, item2;

Способ, которым вы сериализуете его в буфер:

unsigned char arr[20] = {0};
memcpy(arr, &item1.lat, sizeof(int));
memcpy(&arr[1 * sizeof(int)], &item1.lon, sizeof(int));
memcpy(&arr[2 * sizeof(int)], &item2.lat, sizeof(int));
memcpy(&arr[3 * sizeof(int)], &item2.lon, sizeof(int));

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

Теперь у вас есть байтовый массив (который содержит два PointFull объекты — для большего количества объектов вы должны следовать аналогичному подходу), и вы можете использовать его в своей записи:

write(fd, arr, 20);

После чтения байтового массива вы можете восстановить точечные объекты, используя аналогичные memcpy вызовы как выше (только назначение было бы точечными объектами теперь). Но проблема в том, что целочисленная сериализация в двоичном коде не является переносимой (и, кроме того, плавающей) — в разных системах целые числа могут иметь разный размер, различный порядковый номер.
С поплавками их представление может отличаться.

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

PS. Вот является пост, который объясняет сериализацию (для части кодирования с плавающей точкой вы можете использовать ссылку в моем ответе).

3

Другие решения

Если вы просто хотите записать структуры в файл, вы можете просто написать их напрямую:

write(fd, &item1, sizeof (item1));
write(fd, &item2, sizeof (item2));
...

Если у вас их действительно мало, все будет работать нормально, сама ОС буферизует доступ к файловой системе.

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

class BufferWriter {
char *ptr;
int current;
public:
BufferWriter( void *ptr ) : ptr((char*)ptr), current(0) {}
template<typename T>
void Write( const T &t ) {
memcpy(&ptr[current], &t, sizeof(t) );
current += sizeof(t);
}
int GetTotalLength() {
return current;
}
};

И затем используйте это так:

char *b = new char[ENOUGH];
BufferWriter buffer(b);

buffer.Write(item1);
buffer.Write(item2);
...

write(fd, b, buffer.GetTotalLength());
delete[] b;

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

Что касается переносимости файла, который вы выводите (если вы планируете перенести его на другое устройство), вы можете использовать intX_t (Например: int32_t) вместо int, short или что угодно, чтобы быть уверенным в размере. Также для целых чисел вам, возможно, придется проверять порядковый номер системы, но на личных устройствах он всегда будет иметь порядковый номер. Вам не нужно беспокоиться о float а также doubleпотому что все современные устройства используют норму IEEE 754, и даже большинство экзотических устройств также придерживаются этого.

0

По вопросам рекламы [email protected]