Capnp:移动到 BufferedInputStreamWrapper 中的上一个位置
Capnp: Move to previous position in BufferedInputStreamWrapper
我有一个二进制文件,其中包含我想读取的多个 Capnp 消息。按顺序阅读效果很好,但我有一个用例,我想跳转到以前已知的位置。
带有元数据的数据序列图像包括时间戳。我希望有可能来回跳转(就像在视频播放器中一样)。
这是我试过的:
int fd = open(filePath.c_str(), O_RDONLY);
kj::FdInputStream fdStream(fd);
kj::BufferedInputStreamWrapper bufferedStream(fdStream);
for (;;) {
kj::ArrayPtr<const kj::byte> framePtr = bufferedStream.tryGetReadBuffer();
if (framePtr != nullptr) {
capnp::PackedMessageReader message(bufferedStream);
// This should reset the buffer to the last read message?
bufferedStream.read((void*)framePtr.begin(), framePtr.size());
// ...
}
else {
// reset to beginning
}
}
但是我得到这个错误:
capnp/serialize.c++:186: failed: expected segmentCount < 512; Message has too many segments
我假设 tryGetReadBuffer()
returns 下一条打包消息的位置和大小。但话又说回来,BufferedInputStream 应该如何知道 "a message" 是什么。
问题:如何获取消息的位置和大小并稍后从 BufferedInputStreamWrapper 读取这些消息?
替代方案:读取整个文件一次,获取数据的所有权并将其保存到向量中。如此处所述 (https://groups.google.com/forum/#!topic/capnproto/Kg_Su1NnPOY)。一直以来都是更好的解决方案?
BufferedInputStream
不可搜索。为了向后查找,您需要销毁 bufferedStream
然后查找底层文件描述符,例如使用 lseek()
,然后创建一个新的缓冲流。
请注意,如果存在缓冲流,读取当前位置(以便稍后传递给 lseek()
以返回)也很棘手,因为缓冲流将读取过去的位置以便填充缓冲区。您可以通过减去缓冲区大小来计算它,例如:
// Determine current file position, so that we can seek to it later.
off_t messageStartPos = lseek(fd, 0, SEEK_CUR) -
bufferedStream.tryGetReadBuffer().size();
// Read a message
{
capnp::PackedMessageReader message(bufferedStream);
// ... do stuff with `message` ...
// Note that `message` is destroyed at this }. It's important that this
// happens before querying the buffered stream again, because
// PackedMesasgeReader updates the buffer position in its destructor.
}
// Determine the end position of the message (if you need it?).
off_t messageEndPos = lseek(fd, 0, SEEK_CUR) -
bufferedStream.tryGetReadBuffer().size();
bufferedStream.read((void*)framePtr.begin(), framePtr.size());
FWIW,这行的效果是"advance past the current buffer an on to the next one"。在使用 PackedMessageReader
时,您不想这样做,因为它已经提前了流本身。事实上,因为 PackedMessageReader
可能已经超过了当前缓冲区,所以 framePtr
现在可能无效,并且这一行可能会出现段错误。
Alternative: Reading the whole file once, take ownership of the data and save it to a vector. Such as described here (https://groups.google.com/forum/#!topic/capnproto/Kg_Su1NnPOY). Better solution all along?
如果文件适合 RAM,那么预先读取它通常没问题,如果您希望经常来回查找,这可能是个好主意。
另一种选择是mmap()
它。这使得它看起来好像文件在 RAM 中,但操作系统实际上会在您访问它们时按需读取内容。
但是,我认为这实际上不会大大简化代码。现在你要处理一个 ArrayInputStream
(BufferedInputStream
的子类)。要 "seek",您将根据从您要开始的位置开始的缓冲区切片创建一个新的 ArrayInputStream
。
我有一个二进制文件,其中包含我想读取的多个 Capnp 消息。按顺序阅读效果很好,但我有一个用例,我想跳转到以前已知的位置。 带有元数据的数据序列图像包括时间戳。我希望有可能来回跳转(就像在视频播放器中一样)。
这是我试过的:
int fd = open(filePath.c_str(), O_RDONLY);
kj::FdInputStream fdStream(fd);
kj::BufferedInputStreamWrapper bufferedStream(fdStream);
for (;;) {
kj::ArrayPtr<const kj::byte> framePtr = bufferedStream.tryGetReadBuffer();
if (framePtr != nullptr) {
capnp::PackedMessageReader message(bufferedStream);
// This should reset the buffer to the last read message?
bufferedStream.read((void*)framePtr.begin(), framePtr.size());
// ...
}
else {
// reset to beginning
}
}
但是我得到这个错误:
capnp/serialize.c++:186: failed: expected segmentCount < 512; Message has too many segments
我假设 tryGetReadBuffer()
returns 下一条打包消息的位置和大小。但话又说回来,BufferedInputStream 应该如何知道 "a message" 是什么。
问题:如何获取消息的位置和大小并稍后从 BufferedInputStreamWrapper 读取这些消息?
替代方案:读取整个文件一次,获取数据的所有权并将其保存到向量中。如此处所述 (https://groups.google.com/forum/#!topic/capnproto/Kg_Su1NnPOY)。一直以来都是更好的解决方案?
BufferedInputStream
不可搜索。为了向后查找,您需要销毁 bufferedStream
然后查找底层文件描述符,例如使用 lseek()
,然后创建一个新的缓冲流。
请注意,如果存在缓冲流,读取当前位置(以便稍后传递给 lseek()
以返回)也很棘手,因为缓冲流将读取过去的位置以便填充缓冲区。您可以通过减去缓冲区大小来计算它,例如:
// Determine current file position, so that we can seek to it later.
off_t messageStartPos = lseek(fd, 0, SEEK_CUR) -
bufferedStream.tryGetReadBuffer().size();
// Read a message
{
capnp::PackedMessageReader message(bufferedStream);
// ... do stuff with `message` ...
// Note that `message` is destroyed at this }. It's important that this
// happens before querying the buffered stream again, because
// PackedMesasgeReader updates the buffer position in its destructor.
}
// Determine the end position of the message (if you need it?).
off_t messageEndPos = lseek(fd, 0, SEEK_CUR) -
bufferedStream.tryGetReadBuffer().size();
bufferedStream.read((void*)framePtr.begin(), framePtr.size());
FWIW,这行的效果是"advance past the current buffer an on to the next one"。在使用 PackedMessageReader
时,您不想这样做,因为它已经提前了流本身。事实上,因为 PackedMessageReader
可能已经超过了当前缓冲区,所以 framePtr
现在可能无效,并且这一行可能会出现段错误。
Alternative: Reading the whole file once, take ownership of the data and save it to a vector. Such as described here (https://groups.google.com/forum/#!topic/capnproto/Kg_Su1NnPOY). Better solution all along?
如果文件适合 RAM,那么预先读取它通常没问题,如果您希望经常来回查找,这可能是个好主意。
另一种选择是mmap()
它。这使得它看起来好像文件在 RAM 中,但操作系统实际上会在您访问它们时按需读取内容。
但是,我认为这实际上不会大大简化代码。现在你要处理一个 ArrayInputStream
(BufferedInputStream
的子类)。要 "seek",您将根据从您要开始的位置开始的缓冲区切片创建一个新的 ArrayInputStream
。