4

我想创建一个iostream适配器类,它可以让我即时修改写入流或从流中读取的数据。适配器本身应该iostream允许对第三方代码真正透明。

StreamEncoder派生自的类的示例std::ostream

// External algorithm, creates large amounts of log data
int foo(int bar, std::ostream& logOutput);

int main()
{
    // The target file
    std::ofstream file("logfile.lzma");
    // A StreamEncoder compressing the output via LZMA
    StreamEncoder lzmaEncoder(file, &encodeLzma);
    // A StreamEncoder converting the UTF-8 log data to UTF-16
    StreamEncoder utf16Encoder(lzmaEncoder, &utf8ToUtf16);

    // Call foo(), but write the log data to an LZMA-compressed UTF-16 file
    cout << foo(42, utf16Encoder);
}

据我所知,我需要创建一个新basic_streambuf的派生类并将其嵌入到basic_ostream子类中,但这似乎相当复杂。

有没有更简单的方法可以做到这一点?

4

1 回答 1

4

奇怪的是,至少因为事情真的要工作,这些都不应该直接涉及 iostreams 和/或 streambufs。

我会将 iostream 视为媒人类。iostream 有一个 streambuf,它为某种外部数据源/接收器提供缓冲接口。它还具有处理所有格式的语言环境。iostream 只不过是让这两个人一起玩得很好的操场监督员(可以这么说)。由于您正在处理数据格式,因此所有这些都(或应该)在语言环境中处理。

但是,语言环境并不是单一的——它由许多facets 组成,每个 s 都专门用于数据格式化的一个特定部分。在这种情况下,您可能关心的部分是codecvtfacet,它用于(几乎完全)在从 iostream 读取/写入到 iostream 的数据的外部和内部表示之间进行转换。

然而,无论好坏,一个语言环境一次只能包含一个codecvt 方面,而不是像您正在考虑的那样一连串。因此,您真正需要/想要的是一个包装类,它提供一个 codecvt 作为其外部接口,但允许您在 I/O 期间链接一些要对数据执行的任意转换集。

对于 utf 到 utf 的转换,Boost.locale 提供了 utf_to_utf 函数,以及 codecvt 封装代码,所以做这部分的转换简单明了。

以免有人建议用 ICU 来做这些事情,我要补充一点,Boost.Locale 几乎是 ICU 的包装,所以这或多或少是相同的答案,但形式对 C++ 更友好(而 ICU本身就很像 Java,而且对 C++ 几乎是公然敌对的)。

事情的另一面是编写 codecvt facet 给一个相当简单的任务增加了很多复杂性。过滤流缓冲区(例如)通常容易编写。它仍然没有你想的那么简单,但也没有 codecvt 方面那么糟糕。正如@Flexo 已经提到的,Boost iostreams 库已经包含一个过滤流缓冲区,它可以进行 zip 压缩。对 lzma(或 lzh、算术等压缩)进行大致相同的操作相对容易,至少假设您具有易于使用的压缩功能(您基本上只是为它们提供输入缓冲区,它们提供的缓冲区为结果)。

于 2012-07-15T20:19:35.777 回答