c++从文件的一部分加载数据
C++ loading data from part of a file
我想在一个文件中保留一堆简单的结构体(每个结构体目前只有3个int),并且能够在任何给定的时间读取这些结构体中的一个。
作为第一步,我尝试将它们输出到一个文件,然后使用boost::序列化将它们读取回来。目前我正在这样做,这会崩溃:
std::array<Patch, 3> outPatches;
outPatches[0].ZOrigin = 0;
outPatches[0].XOrigin = 0;
outPatches[0].Resolution = 64;
outPatches[1].ZOrigin = 1;
outPatches[1].XOrigin = 5;
outPatches[1].Resolution = 3;
outPatches[2].ZOrigin = 123;
outPatches[2].XOrigin = 546;
outPatches[2].Resolution = 6;
std::ofstream ofs("testing.sss", std::ios::binary);
for (auto const& patch : outPatches)
{
std::cout << "start archive: " << ofs.tellp() << std::endl;
{
boost::archive::binary_oarchive oa(ofs);
std::cout << "start patch: " << ofs.tellp() << std::endl;
oa << patch;
}
}
ofs.close();
std::array<Patch, 3> inPatches;
std::ifstream ifs("testing.sss", std::ios::binary);
for (auto& patch : inPatches)
{
std::cout << "start archive: " << ifs.tellg() << std::endl;
{
boost::archive::binary_iarchive ia(ifs); // <-- crash here on second patch
std::cout << "start patch: " << ifs.tellg() << std::endl;
ia >> patch;
}
}
ifs.close();
for (int i = 0; i != 3; ++i)
std::cout << "check: " << (inPatches[i] == outPatches[i]) << std::endl;
我计划使用tell来创建每个结构的索引,并寻求在加载时跳转到该结构。这是一个合理的方法吗?除了基础知识,我对流知之甚少。
我试过把所有的补丁放在一个o/iarchive中,这样可以很好地按顺序读取所有内容。但是,在流上查找不工作。
我发现了这个,这可能是我想要的,但我不知道它在做什么或如何使用它,或者它是否会与boost::serialization: read部分文件与iostreams
如果有必要的话,我可能愿意切换到另一种序列化方法,因为我在这方面还没有走得太远。
Edit 3:将编辑1和2移动到答案
我曾经遇到过类似的情况(使用boost/serialization)。我当时所做的(如果我记得的话,这是相当有效的)是将文件映射到虚拟地址,编写一个对内存缓冲区而不是文件进行操作的streamer,对于我想要读取的每个部分,为streamer分配适当的偏移量作为缓冲区开始/长度,并使用streamer初始化iarchive,因此序列化库将其视为每个对象都在一个单独的文件中。
当然,添加到文件中需要重新映射。现在我回头看,这似乎有点奇怪,但它是有效的,公平的。
Boost序列化
似乎不可能在boost序列化存档中跳过。到目前为止,我得到的最好的方法是在一个流上使用多个存档:
static const int numPatches = 5000;
std::vector<int> indices(numPatches, 0);
std::iota(indices.begin(), indices.end(), 0);
std::vector<Patch> outPatches(numPatches, Patch());
std::for_each(outPatches.begin(), outPatches.end(),
[] (Patch& p)
{
p.ZOrigin = rand();
p.XOrigin = rand();
p.Resolution = rand();
});
std::vector<int64_t> offsets(numPatches, 0);
std::ofstream ofs("testing.sss", std::ios::binary);
for (auto i : indices)
{
offsets[i] = ofs.tellp();
boost::archive::binary_oarchive oa(ofs,
boost::archive::no_header | boost::archive::no_tracking);
oa << outPatches[i];
}
ofs.close();
std::random_shuffle(indices.begin(), indices.end());
std::vector<Patch> inPatches(numPatches, Patch());
std::ifstream ifs("testing.sss", std::ios::binary);
for (auto i : indices)
{
ifs.seekg(offsets[i]);
boost::archive::binary_iarchive ia(ifs,
boost::archive::no_header | boost::archive::no_tracking);
ia >> inPatches[i];
ifs.clear();
}
std::cout << std::all_of(indices.begin(), indices.end(),
[&] (int i) { return inPatches[i] == outPatches[i]; }) << std::endl;
不幸的是,这是非常慢的,所以我认为我不能使用它。下一步是测试protobuf。
谷歌:protobuf
我有一些工作与protobuf。它需要一些改动(显然我必须使用LimitingInputStream类型,并存储每个对象的大小),但它比boost::serialization版本快得多:
static const int numPatches = 500;
std::vector<int> indices(numPatches, 0);
std::iota(indices.begin(), indices.end(), 0);
std::vector<Patch> outPatches(numPatches, Patch());
std::for_each(outPatches.begin(), outPatches.end(),
[] (Patch& p)
{
p.ZOrigin = rand();
p.XOrigin = rand();
p.Resolution = 64;
});
std::vector<int64_t> streamOffset(numPatches, 0);
std::vector<int64_t> streamSize(numPatches, 0);
std::ofstream ofs("testing.sss", std::ios::binary);
PatchBuffer buffer;
for (auto i : indices)
{
buffer.Clear();
WriteToPatchBuffer(buffer, outPatches[i]);
streamOffset[i] = ofs.tellp();
streamSize[i] = buffer.ByteSize();
buffer.SerializeToOstream(&ofs);
}
ofs.close();
std::random_shuffle(indices.begin(), indices.end());
std::vector<Patch> inPatches(numPatches, Patch());
std::ifstream ifs("testing.sss", std::ios::binary);
for (auto i : indices)
{
ifs.seekg(streamOffset[i]);
buffer.Clear();
google::protobuf::io::IstreamInputStream iis(&ifs);
google::protobuf::io::LimitingInputStream lis(&iis, streamSize[i]);
buffer.ParseFromZeroCopyStream(&lis);
ReadFromPatchBuffer(inPatches[i], buffer);
ifs.clear();
}
std::cout << std::all_of(indices.begin(), indices.end(),
[&] (int i) { return inPatches[i] == outPatches[i]; }) << std::endl;
- 使用ifstream从DAT文件加载数据
- SqlDataAdapter 未加载数据表 - C++
- C ,MySQL API加载数据本地
- 使用提升库在队列和堆栈数据结构上保存和加载数据时出错
- 使用 fstream 从文件加载数据
- 从文件加载数据
- 将错误处理添加到加载数据的函数(但有时还需要使用默认值)
- C#从文件加载数据并分类为数组
- 保存/加载C++数据时出错
- C++简体版链表,当我加载数据以创建链表并输入更多数据时,似乎存在差距
- 我无法加载数据文件,总是无法打开它
- 从C++模拟中保存和加载数据的有效方法
- 快板 5 加载数据文件
- 通过C++虚幻引擎改进加载数据
- 使用套接字从页面加载数据
- 创建缓冲区以加载数据时出错
- 使用 boost 序列化到磁盘后无法加载数据
- 从C++中的CSV文件读取和加载数据时出现问题
- 如何在运行时通过插件机制动态加载数据类型
- 保存和加载数据C++