简体   繁体   English

创建std :: iostream适配器

[英]Creating a std::iostream adapter

I'd like to create an iostream adapter class which lets me modify the data written to or read from a stream on-the-fly. 我想创建一个iostream适配器类,它允许我在运行中修改写入或读取流的数据。 The adapter itself should be a iostream to allow true transparency towards third-party code. 适配器本身应该是一个iostream以实现对第三方代码的真正透明。

Example for a StreamEncoder class derived from std::ostream : std::ostream派生的StreamEncoder类的示例:

// 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);
}

As far as I know, I need to create a new basic_streambuf derivate and embed it in a basic_ostream subclass, but that seems to be pretty complex. 据我所知,我需要创建一个新的basic_streambuf派生并将其嵌入basic_ostream子类中,但这似乎相当复杂。

Is there any easier way to accomplish this? 有没有更简单的方法来实现这一目标?

Oddly enough, at least as things are really intended to work, none of this should directly involve iostreams and/or streambufs at all. 奇怪的是,至少在事情确实有效的情况下,这些都不应该直接涉及到iostreams和/或streambufs。

I would think of an iostream as a match-maker class. 我会把iostream想象成一个匹配者类。 An iostream has a streambuf which provides a buffered interface to some sort of external source/sink of data. iostream有一个streambuf,它为某种外部数据源/接收器提供缓冲接口。 It also has a locale, which handles all the formatting. 它还有一个区域设置,可以处理所有格式。 The iostream is little more than the playground supervisor that keeps those two playing together nicely (so to speak). iostream不仅仅是游乐场的主管,让这两个人在一起玩得很好(可以这么说)。 Since you're dealing with data formatting, all of this is (or should be) handled in the locale. 由于您正在处理数据格式化,因此所有这些都是(或应该)在语言环境中处理。

A locale isn't monolithic though -- it's composed of a number of facet s, each devoted to one particular part of data formatting. 虽然语言环境不是单一的 - 它由许多facet组成,每个facet都专门用于数据格式化的一个特定部分。 In this case, the part you probably care about is the codecvt facet, which is used (almost exclusively) to translate between the external and internal representations of data being read from/written to iostreams. 在这种情况下,您可能关心的部分是codecvt facet,它(几乎唯一地)用于在从iostreams读取/写入的数据的外部和内部表示之间进行转换。

For better or worse, however, a locale can only contain one codecvt facet at a time, not a chain of them like you're contemplating. 然而,无论好坏,一个语言环境一次只能包含一个 codecvt方面,而不是像你正在考虑的那样。 As such, what you really need/want is a wrapper class that provides a codecvt as its external interface, but allows you to chain some arbitrary set of transforms to be done to the data during I/O. 因此,您真正需要/想要的是一个包装类,它提供了一个codecvt作为其外部接口,但允许您在I / O期间链接一些任意的变换集。

For the utf-to-utf conversion, Boost.locale provides a utf_to_utf function, and codecvt wrapper code, so doing this part of the conversion is simple and straightforward. 对于utf-to-utf转换,Boost.locale提供了utf_to_utf函数和codecvt包装器代码,因此执行此部分转换非常简单明了。

Lest anybody suggest that such things be done with ICU, I'll add that Boost.Locale is pretty much a wrapper around ICU, so this is more or less the same answer, but in a form that's much more friendly to C++ (whereas ICU by itself is rather Java-like, and all but overtly hostile to C++). 为了避免有人建议用ICU完成这些事情,我会补充说Boost.Locale几乎是ICU的一个包装器,所以这或多或少是相同的答案,但是对C ++更友好的形式(而ICU)它本身就像Java一样,而且几乎完全不喜欢C ++)。

The other side of things is that writing a codecvt facet adds a great deal of complexity to a fairly simple task. 事情的另一面是编写一个codecvt方面为一个相当简单的任务增加了很多复杂性。 A filtering streambuf (for one example) is generally a lot simpler to write. 过滤streambuf(例如)通常编写起来简单得多。 It's still not as easy as you'd like, but not nearly as bad as a codecvt facet. 它仍然不是你想要的那么容易,但并不像codecvt方面那么糟糕。 As @Flexo already mentioned, the Boost iostreams library already includes a filtering streambuf that does zip compression. 正如@Flexo已经提到的,Boost iostreams库已经包含了一个压缩压缩的过滤streambuf。 Doing roughly the same with lzma (or lzh, arithmetic, etc. compression) is relatively easy, at least assuming you have compression functions that are easy to use (you basically just supply them with a buffer of input, and they supply a buffer of results). 与lzma(或lzh,算术等压缩)大致相同是相对容易的,至少假设你有易于使用的压缩函数(你基本上只为它们提供输入缓冲区,并且它们提供缓冲区结果)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM