我有一个具有以下结构的二进制文件:
+---------+-------+------+----+-------+
|页眉 |对象1 |Obj2 |... |首页 |
+---------+-------+------+----+-------+
Index
是一个可变大小的向量,取决于对象的数量,并存储每个对象的文件位置。 例如
vector<size_t> index;
index.push_back(ofs.tellp());
write(reinterpret_cast<char *> obj, sizeof(obj));
此外,文件非常大(1Gb+)。
我想把索引放在标题之后,这样阅读起来更快。我可以在不必复制和写入所有对象两次的情况下执行此操作吗?谢谢。
您有两种解决方案:
- 为索引使用单独的文件
- 转向基于块的设计
第一个相对明显,所以我只概述第二个:这里的问题是索引大小取决于你流式传输的对象数量。它不一定是这样。
一个解决方案是跳过一定数量的空间(稍后用于索引),流式传输对象(最多 N),记录您所在的位置,返回索引将其写下来,然后继续下一个块(注意:块在这里不是固定大小)。
布局示例:
- Step 1: skip index space and start streaming objects
| Header | <unused space for now> | Obj 1 | Obj 2 | O3 | ... Obj N |
- Step 2: after writing N objects write the index,
record the offset,
start a new chunk
| Header | I1 | ... | IN | Offset | Obj 1 | Obj 2 | O3 | ... Obj N | <unused sp
因此,您的索引被构建为在存储中间交错的固定大小块 (N) 的链接列表。
注意:第三种解决方案是使用一个简单的SQLite文件并让它为您索引...
写入文件时计算您有多少对象。
nObjects // Number of objects
那么你将需要
indexSize = nObjects * sizeof(size_t);
开始写入对象
ofs.seekp(indexSize + headerSize)
写入所有对象
index.push_back(ofs.tellp());
write(reinterpret_cast<char *> obj, sizeof(obj));
移动到索引的开头 ofs.seekp(headerSize);
写入索引
我认为答案是否定的,但是如果您有低级文件系统工具并且知道如何操作您选择的文件系统,您也许能够做到这一点。
假设,您正在使用旧的愚蠢的 FAT,其中 FAT 表存储有关文件所在的磁盘扇区的信息,然后您可以为索引分配扇区,然后修改与您的文件相关的 FAT 表条目以指定磁盘上扇区的新顺序为您的文件,本质上是重新排序而不重新保存整个东西。
这将如何与 NTFS、ZFS 等一起工作 - 我不知道,但如果不对 NTFS 结构进行操作,我很确定这是不可能的。
有意义吗?