创建一个 std::iostream 适配器
Creating a std::iostream adapter
我想创建一个iostream
适配器类,它允许我即时修改写入流或从流读取的数据。适配器本身应该是一种iostream
,以允许对第三方代码真正透明。
派生自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);
}
据我所知,我需要创建一个新的basic_streambuf
派生并将其嵌入到basic_ostream
子类中,但这似乎非常复杂。
有没有更简单的方法来实现这一点?
奇怪的是,至少当事情真正打算工作时,这一切都不应该直接涉及iostreams和/或streambufs。
我会认为iostream是一个媒人类。iostream有一个streambuf,它为某种外部数据源/接收器提供了一个缓冲接口。它还有一个区域设置,用于处理所有格式。iostream只不过是让这两个人很好地一起玩耍的操场主管(可以这么说(。由于您正在处理数据格式,因此所有这些都(或应该(在区域设置中处理。
不过,区域设置不是单一的 - 它由许多facet
组成,每个专用于数据格式的一个特定部分。在这种情况下,您可能关心的部分是codecvt
方面,它(几乎专门(用于在从iostream读取/写入iostream的数据的外部和内部表示之间进行转换。
但是,无论好坏,区域设置一次只能包含一个编解码器分面,而不是像您正在考虑的那样包含它们的链。因此,您真正需要/想要的是一个包装类,它提供编解码器作为其外部接口,但允许您链接一些任意一组要在 I/O 期间对数据执行的转换。
对于utf到utf的转换,Boost.locale提供了一个utf_to_utf函数和codecvt包装代码,因此完成这部分转换既简单又直接。
为了避免有人建议用ICU做这样的事情,我要补充一点,Boost.Locale几乎是ICU的包装器,所以这或多或少是相同的答案,但形式对C++更友好(而ICU本身相当类似于Java,并且几乎公开敌视C++(。
另一方面,编写编解码器方面会给相当简单的任务增加很多复杂性。过滤流(例如(通常编写起来要简单得多。它仍然不像您想要的那么容易,但并不像编解码器方面那么糟糕。正如@Flexo已经提到的,Boost iostreams库已经包含一个执行zip压缩的过滤streambuf。对 lzma(或 lzh、算术等压缩(做大致相同的操作相对容易,至少假设你有易于使用的压缩函数(你基本上只是为它们提供一个输入缓冲区,它们提供结果缓冲区(。
- 使用std::multimap迭代器创建std::list
- std::带有自定义缓冲区的 iostream 不允许我写入
- 为什么我必须在包含后写 std::cin <iostream>?
- 如何将带有空字符的字节数组馈送到 std::iostream 中?
- C++:为什么 std::greater<T>() 包含在 iostream 中?
- Printing CComBSTR with iostream (std::wcout)
- 为什么我们应该在使用"using namespace std"时使用"#include<iostream>"?
- 将 boost::iostream::stream<boost::iostreams::source> 转换为 std::istream
- 是std :: iostream非阻滞
- 调整 C++ std/boost iostream 以提供对内存块的循环写入
- 如何将上下文信息传递给自定义运算符<<适用于 std::iostream
- 错误:标识符"cout"未定义。<iostream> 包含并使用命名空间 std;
- 创建一个 std::iostream 适配器
- G++ 找不到 std 标头(iostream、string 等)
- 我应该避免从std::iostream继承吗
- 如何在读写时禁用std::iostream try catch
- iostream和命名空间std之间的关系是什么?
- #include <iostream> 使用 -std=c++11 给出错误
- std::iostream读取或写入计数为零且缓冲区无效
- C++ iostream 的包装类,请使用带有运算符的 std::endl 等流修饰符<<