如何将多个对象(或任何数据)读写到缓冲区?

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

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

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 调用来重建点对象(现在目标就是点对象成员)。但问题是二进制整数序列化是不可移植的(而且是浮动的)——在不同的系统上,整数可能有不同的大小、不同的字节顺序。 对于花车,它们的表示可能会有所不同。

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

PS。这里 is post 解释了序列化(对于浮点编码部分,您可以在我的回答中使用 link)。

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

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

除非你真的有很多,否则它会正常运行,OS 本身会缓冲文件系统访问。

如果你真的想使用缓冲区,你可以有一个小的class来写入缓冲区:

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 或任何确定大小的内容。同样对于整数,您可能必须检查系统的字节顺序,但在个人设备上它总是小字节序。你不必担心 floatdouble,因为所有现代设备都使用 IEEE 754 规范,甚至大多数外来设备也坚持这一点。