前言
c++原生的流处理并不支持流的压缩处理,因此需要使用boost库的流处理。
boost流处理
即boost.iostreams库,我需要用到的组成部分如下:
- device(设备) - 流的起点source(源设备),流的终点sink(目标设备)
- filter(过滤器) - 读取数据时的输入过滤器,写入数据时的输出过滤器
- stream(流) - 用来连接设备和过滤器,实现类似标准流的功能
前置编译
iostreams库是一个由头文件组成的库,位于<boost/iostreams/> 下,分为无需编译的功能和需要编译才能使用的功能。 而需要用到的压缩功能则要进行其他库的额外安装,这里就用bzip2举例。
sudo apt-get install libbz2-dev
使用该命令安装bzip2的库,就可以在boost的流处理中使用bzip2格式的压缩了。
惯例用法
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/filtering_stream.hpp>
namespace io = boost::iostreams;
using namespace io;
设备
设备最基本的特征是能够处理“字符类型”。
设备模式
- 输入模式(input)
- 输出模式(output)
- 双向模式(bidirectional) 既可以输入,也可以输出
- 可定位模式(seekable) 可重定位操作的位置
- 可定位输入模式(input-seekable)
- 可定位输出模式(output-seekable)
我需要使用的就是可定位输入模式和可定位输出模式。
设备类型
字符类型和访问模式是设备最重要的两个特征,除此以外,设备的类型(原设备、接收设备、过滤器)也可作为分类的依据。特征的标签位于<boost/iostreams/categories.hpp> 中。 判断一个类是否为设备可以使用原函数is_device<T> 。
自定义设备
可以根据<boost/iostreams/concepts.hpp> 中定义的设备的子概念来进行扩展。 比如source和sink两个类。
预定义设备
这里就简单列举一下,因为使用不到,就不详细了解了。
标准容器设备
boost.range库中提供的函数boost::make_iterator_range()可以把容器传递给过滤流从而创建出可以用于输入的流。
文件设备
是我需要使用的,也是要学习的重点。 位于<boost/iostreams/device/file.hpp> 中,基于标准库的文件流提供了对文件的访问。 分为以下三类:
- file_source 源设备
- file_sink 目标设备
- file 可定位设备
过滤器
由于其他过滤器暂时不适用,这里只介绍一下压缩过滤器的用法。 bzip2的头文件位于<boost/iostreams/filter/bzip2.hpp> 中,使用方法很简单:
string str("test");
string zip_str,unzip_str;
filtering_ostream fout(
bzip2_compressor() | io::back_inserter(zip_str));
io::copy(
boost::make_iterator_range(str)
,zout);
filtering_ostream unzip_out(
bzip2_decompressor() | io::back_inserter(unzip_str));
io::copy(
boost::make_iterator_range(zip_str),
unzip_out);
std::cout<<upzip_str<<std::endl;
流
分为基本流和过滤流,基本流一般使用stream,过滤流是基本流的强化版,可以在连接设备的基础上连接过滤器和链,过滤流一般使用filtering_stream。
流处理函数
最为重要的是io::copy(),其位于头文件<boost/iostreams/copy.hpp> 中。 其声明:
template<typename Source,typename Sink>
std::streamsize copy(Source &src,Sink &sink);
常用的函数<boost/iostreams/operations.hpp> :
- get(d) 从源设备或流中获取一个字符
- read(d,s,n) 从源设备或流中获取多个字符
- put(d,c) 向接收设备或流中写入一个字符
- write(d,s,n) 向接收设备或流中写入多个字符
- seek(d,off,way) 随机访问设备或流
- flush(d) 刷新设备或整个流,清空缓冲区
- close(d) 关闭设备或流
参数说明:d是device的缩写,指设备,s为size的缩写,指大小,off为offset的缩写,指偏移量,c为char的缩写,指字符,way指访问方式。
hello world
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/operations.hpp>
#include <bzlib.h>
namespace io = boost::iostreams;
using namespace io;
using namespace std;
int main()
{
file_sink fsink("test.txt");
filtering_ostream out(
bzip2_compressor() | fsink
);
char buf[] = "test 1 2 3 4";
io::write(out,buf,sizeof(buf));
io::close(out);
file_source fsource("test.txt");
filtering_istream in;
in.push(bzip2_decompressor());
in.push(fsource);
char a[64];
io::read(in,a,64);
printf("%s\n",a);
fsource.close();
}
CMakeLists.txt文件
cmake_minimum_required(VERSION 3.0.2)
set(CMAKE_CXX_STANDARD 14)
project(Test)
add_definitions(-std=c++11)
add_definitions(-g -o3)
find_package(Boost REQUIRED COMPONENTS filesystem iostreams)
find_package(BZip2 REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
include_directories(${BZIP2_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIRS})
link_directories(${BZIP2_LIBRARY_DIRS})
add_definitions(${BZIP2_DEFINITIONS})
set(SRC
src/test.cpp
)
add_executable(zip_test ${SRC})
target_link_libraries(zip_test -lm -lstdc++ ${BZIP2_LIBRARIES} ${Boost_LIBRARIES})
可以看到,这一demo成功完成了压缩解压缩的过程。
参考文献
《C++11/14高级编程:Boost程序库探秘(第3版)》
|