Я пишу программу для сохранения некоторого объекта (структуры) в буфер. У меня нет эксперимента, чтобы записать много объектов в буфер и прочитать эти объекты из буфера. Любая помощь будет оценена.
Мой код может записать один элемент в объект, и я хочу записать много объектов в буфер
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 элементов, но я не знаю, как читать буфер для вставки данных в структуру ??? Пожалуйста, помогите мне!
Ну, что вы хотите сделать, это сериализация. Скажем, у вас есть такая структура:
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. Вот является пост, который объясняет сериализацию (для части кодирования с плавающей точкой вы можете использовать ссылку в моем ответе).
Если вы просто хотите записать структуры в файл, вы можете просто написать их напрямую:
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, и даже большинство экзотических устройств также придерживаются этого.