【问题标题】:How to correctly read from already opened std::ifstream using a buffer如何使用缓冲区正确读取已打开的 std::ifstream
【发布时间】:2017-06-12 15:27:58
【问题描述】:

背景

我实现了一个 JSON 解析器并提供了一个 operator>> 函数来解析 std::ifstream。为了加快读取速度,我将 16 KB 复制到缓冲区中,并让解析器从缓冲区中读取。一个小型基准测试表明,这比直接使用 std::ifstream::getstd::ifstream::read 更快。

当前(错误?)实现

当我成功读取 JSON 值时,我想将缓冲区中所有不必要的字节“放回”到流中,以便随后使用相同的 std::istream 调用 operator>> 继续在第一次调用结束的地方进行解析。我目前像这样实现这个“放回”:

is.clear();
is.seekg(start_position + static_cast<std::streamoff>(processed_chars));
is.clear();

因此,is 是输入文件流,start_positionis.tellg() 的初始值,processed_chars 是解析器读取的字符数。

这适用于 GCC 和 Clang 以及 OSX 和 Linux,但 MSVC 2015 和 MSVC 2017 无法将输入流带入所需状态。

我的问题

  1. 显然,我在这里做错了什么。不同的编译器不应该表现得如此不同。 clear() 调用已经是使代码在 GCC/Clang 下运行的反复试验的结果。

  2. (a) 使用缓存从已打开的 std::ifstream 读取和 (b) 能够在最后一个处理的字符之后(而不是在最后一个缓存的字符之后)恢复解析的正确方法是什么?

  3. 有没有更好的方法来快速读取已经打开的std::ifstream?正如我上面提到的,删除缓存会使解析器变慢。

(对这个幼稚的问题和糟糕的实现表示歉意!我没有找到解决已经打开的std::ifstream 或者可以“放回”已经缓存的字符的答案。)

【问题讨论】:

  • hmmm 你真的需要它在 MSVC 下编译吗?您甚至可以在 linux/Mac 机器上使用 GCC/Clang 创建 Windows 可执行文件,对吧?
  • 您可以通过编写自定义::std::streambuf 实现来创建自定义缓冲文件流。
  • @niceman 最后,我只发布了一个可以在任何地方编译的标头,请参阅github.com/nlohmann/json
  • @VTT 我可以将此自定义缓冲区与传递的std::ifstream 对象一起使用吗?以及如何将字符从缓冲区“放回”到流中?
  • 通常你会在创建时将streambuf 实例指针传递给istream,并且根本不需要使用ifstream。只要您在 streambuf 实现中提供相应的重载,stream 就会处理“放回”和其他操作。

标签: c++ caching ifstream


【解决方案1】:

如果您以文本模式打开文件流,这是无效的:

is.seekg(start_position + static_cast<std::streamoff>(processed_chars));

...因为根据标准,seekg / tellg 与处理的字符数没有直接关系(这实际上是依赖于操作系统的)。

以下是您可能的选择(无法详细说明您在问题中提供的内容):

  • 使用putback 放回您阅读但未使用的字符;
  • 使用tellg 获取正确的位置。

可能是这样的:

// is is the istream
auto tg = is.tellg();
is.read(buffer, BUFFER_SIZE);
 // process...
is.seekg(tg); // valid
is.ignore(processed_chars);

【讨论】:

    猜你喜欢
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    相关资源
    最近更新 更多