平衡文件空间,内存访问和写入速度的结构数组到文件

Balancing file space, memory access and write speed for writing array of struct to file

本文关键字:速度 结构 数组 文件 文件空间 内存 访问 平衡      更新时间:2023-10-16

我正在寻找一种方法来保存一个结构体的矢量,以占用文件上最少的空间。我读到#pragma pack可以完成(从这里开始),然后写作可以完成如下:

#pragma pack(push,1)
struct GroupedData {
    double m_average;
    int m_count;
    char m_identifier;
};
#pragma pack(pop)
vector<GroupedData> alldata;
//here alldata is filled with stuff
FILE *file = fopen("datastorage.bin", "wb");
fwrite(&alldata[0],sizeof(GroupedData),alldata.size(),file);
fclose(file);

然而,在这个问题的一个答案中,有人说,由于内存对齐,内存访问数据会慢得多。为了保持内存效率和最小的文件大小,我希望下面的函数能够实现这一点。

struct GroupedData {
    double m_average;
    int m_count;
    char m_identifier;
    void WriteStruct(FILE* file) {
        fwrite(&m_average,sizeof(double),1,file);
        fwrite(&m_count,sizeof(int),1,file);
        fwrite(&m_identifier,sizeof(char),1,file);
    }
};
vector<GroupedData> alldata;
//here alldata is filled with stuff
FILE *file = fopen("datastorage.bin", "wb");
for (size_t i=0; i<alldata.size(); ++i)
    alldata[i].WriteStruct(file);
fclose(file);

然而,这个写函数不会花费更长的时间来执行,因为每个变量都是独立编写的吗?那么,我如何才能"平衡"快速内存访问与最低的文件存储和文件写入速度?

您可以通过更改内存布局来优化所有这些(内存空间,内存访问和写速度)。也就是说,您应该引入另一层来处理内存和磁盘上的数据,一个包含8个条目的块,例如:

struct GroupedDataBlock {
    double m_average[8];
    int m_count[8];
    char m_identifier[8];
};

这样,所有的数据将自然对齐。您将有一个稍微复杂的逻辑来处理元素向量。按照我所建议的想法,我将定义一个类来处理单个GroupedData元素,隐藏以下表示:

class GroupedData {
    GroupedDataBlock *groupedDataBlock;
    int inBlockIndex;
public:
    GroupedData(GroupedDataBlock *gdb, int index) : groupedDataBlock(gdb), inBlockIndex(index) {}
    double &m_average()    {return groupedDataBlock->m_average[inBlockIndex]; }
    int    &m_count()      {return groupedDataBlock->m_count[inBlockIndex]; }
    char   &m_identifier() {return groupedDataBlock->m_identifier[inBlockIndex]; }
};

元素向量也需要一些定制。这里只报告索引,您需要添加逻辑来处理所需的操作(添加元素)。

class GroupedDataVector {
    vector<GroupedDataBlock> alldata;
    size_t actual_size;
public:
    GroupedData operator[] (int i) {return GroupedData(&alldata[i/8], i%8); }
};

写你的文件,你只需要写alldata在一个镜头。唯一的开销将是最终没有完全填充的最后一个块。