如何读取和写入许多对象(或任何数据)到缓冲区

How to read and write many objects (or any data) to a buffer?

本文关键字:任何 多对象 数据 缓冲区 何读取 读取      更新时间:2023-10-16

我正在写一个程序来保存一些对象(结构体)到缓冲区。我没有实验写很多对象到缓冲区和读取这些对象从缓冲区。任何帮助都会很感激。我的代码可以写一个项目到对象,我想写多个对象到缓冲区

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 filen");
    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 filen");
    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中使用它:

write(fd, arr, 20);

读取字节数组后,您可以使用类似的memcpy调用来重建点对象(现在只是目的地将是点对象成员)。但这样做的问题是,二进制的整数序列化是不可移植的(而且是浮点数)——在不同的系统上,整数可能有不同的大小和不同的端序。对于浮点数,它们的表示也可能不同。

无论如何,有一种方法如何在二进制中编码浮点数-检查pack754(和类似的解包)功能。如果你使用这个函数序列化字节数组中的浮点数,并像这个答案一样分别序列化每个浮点数,那么你可能会没事。

<子> p。这是一个解释序列化的帖子(对于浮点编码部分,您可以在我的回答中使用链接)

如果你只想在文件中写入结构,你可以直接写入它们:

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或其他确定大小的文件。同样对于int,您可能需要检查系统的端序,但在个人设备上它将始终是小端序。您不必担心floatdouble,因为所有现代设备都使用IEEE 754规范,甚至大多数外来设备也坚持此规范。