一、Filters说明
除了设备之外,Boost.IOStreams 还提供了过滤器,它在设备前面运行,过滤从设备读取或写入设备的数据。以下示例使用 boost::iostreams::filtering_istream 和 boost::iostreams::filtering_ostream。它们取代了不支持过滤器的 boost::iostreams::stream。
二、过滤器示例
例 34.6。使用 boost::iostreams::regex_filter
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/regex.hpp>
#include <boost/regex.hpp>
#include <iostream>
using namespace boost::iostreams;
int main()
{
char buffer[16];
array_sink sink{buffer};
filtering_ostream os;
os.push(regex_filter{boost::regex{"Bo+st"}, "C++"});
os.push(sink);
os << "Boost" << std::flush;
os.pop();
std::cout.write(buffer, 3);
}
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/counter.hpp>
#include <iostream>
using namespace boost::iostreams;
int main()
{
char buffer[16];
array_sink sink{buffer};
filtering_ostream os;
os.push(counter{});
os.push(sink);
os << "Boost" << std::flush;
os.pop();
counter *c = os.component<counter>(0);
std::cout << c->characters() << '\n';
std::cout << c->lines() << '\n';
}
示例 34.6 使用设备 boost::iostreams::array_sink 将数据写入数组。数据通过 boost::iostreams::regex_filter 类型的过滤器发送,该过滤器替换字符。过滤器需要一个正则表达式和一个格式字符串。正则表达式描述了要替换的内容。格式字符串指定应该用什么字符替换。该示例将“Boost”替换为“C++”。过滤器将匹配“Boost”中字母“o”的一个或多个连续实例,但不匹配零个实例。
过滤器和设备通过流 boost::iostreams::filtering_ostream 连接。这个类提供了一个成员函数 push(),过滤器和设备被传递给它。
过滤器必须在设备之前通过;顺序很重要。您可以传递一个或多个过滤器,但是一旦传递了一个设备,流就完成了,您不能再次调用 push()。
过滤器 boost::iostreams::regex_filter 不能逐字符处理数据,因为正则表达式需要查看字符组。这就是为什么 boost::iostreams::regex_filter 只有在写操作完成并且所有数据都可用后才开始过滤。当使用成员函数 pop() 从流中删除设备时会发生这种情况。例 34.6 在将“Boost”写入流后调用 pop()。如果不调用 pop(),boost::iostreams::regex_filter 将不会处理任何数据,也不会将数据转发到设备。
请注意,您不得使用未与设备连接的流。但是,如果在调用 pop() 后使用 push() 添加设备,则可以完成流。
示例 34.6 显示了 C++。
例 34.7。在 boost::iostreams::filtering_ostream 中访问过滤器
示例 34.7 使用过滤器 boost::iostreams::counter,它计算字符和行数。该类提供了成员函数characters() 和lines()。
boost::iostreams::filtering_stream 提供成员函数 component() 来访问过滤器。相应过滤器的索引必须作为参数传递。因为 component() 是一个模板,所以过滤器的类型必须作为模板参数传递。 component() 返回一个指向过滤器的指针。如果作为模板参数传递了不正确的过滤器类型,则返回 0。
示例 34.7 将五个字符写入流。它不写换行符(“\n”)。因此,该示例显示 5 和 0。
例 34.8。读写 ZLIB 压缩的数据
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <vector>
#include <string>
#include <iostream>
using namespace boost::iostreams;
int main()
{
std::vector<char> v;
back_insert_device<std::vector<char>> snk{v};
filtering_ostream os;
os.push(zlib_compressor{});
os.push(snk);
os << "Boost" << std::flush;
os.pop();
array_source src{v.data(), v.size()};
filtering_istream is;
is.push(zlib_decompressor{});
is.push(src);
std::string s;
is >> s;
std::cout << s << '\n';
}
除了 boost::iostreams::filtering_iostream 之外,示例 34.8 还使用了流 boost::iostreams::filtering_istream。当您想使用过滤器读取数据时使用此流。在示例中,压缩数据被再次写入和读取。
Boost.IOStreams 提供了几个数据压缩过滤器。 boost::iostreams::zlib_compressor 类以 ZLIB 格式压缩数据。要解压缩 ZLIB 格式的数据,请使用类 boost::iostreams::zlib_decompressor。这些过滤器使用 push() 添加到流中。
示例 34.8 将“Boost”写入压缩形式的向量 v 和未压缩形式的字符串 s。该示例显示 Boost。
请注意,在 Windows 上,Boost.IOStreams 预构建库不支持数据压缩,因为默认情况下,该库在 Windows 上使用宏 NO_ZLIB 构建。您必须取消定义此宏,定义 ZLIB_LIBPATH 和 ZLIB_SOURCE,并重新构建以获得 Windows 上的 ZLIB 支持。
练习
创建两个可以压缩和解压缩文件的命令行程序。