您的位置:首页 > 移动开发 > IOS开发

boost::iostreams——谁叫你把0x0a转成0x0d 0x0a的混蛋东西

2016-04-15 16:23 302 查看
先扯点背景知识:Boost Iostreams库是Boost库中一个流编程框架,它把字符流的处理泛化。使用者可以利用该库自行编写流过滤器(Filter)对流进行处理。

其实从学C++开始就一直对流这个概念感到费解,感觉太尼玛抽象了。但自从用了Iostreams这个库后,对流的认识开始深刻起来。说到流,现在我脑海里突然浮现出《疯狂动物城》中的一幕:一群交易员仓鼠排成一排,向狐狸购买冰棍。



萌出了一脸血啊!然而这个和我们的流有什么关系呢?这里我们的仓鼠队伍就可以看成一个流,你可以把仓鼠看成流中的元素,而我们的狐狸先生就是一个流处理器,对每个仓鼠都执行收钱,给冰棍的操作。

联系到实际运用中,比如我们经常要对一些文本进行压缩解压操作,其实就是对一个文本流中的字符进行重复的压缩解压操作。可能是来一个字符,进行一次处理,也有可能是来若干个字符,进行一次处理。你可以据此分别编写compressor和decompressor的filter。而用起来就更简单了,你只需要将这些filter排一排,然后让流经过就行,就像仓鼠们经过狐狸先生一样。

压缩过程的调用方式

#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/filtering_stream.hpp>

namespace io = boost::iostreams;

int main()
{
io::filtering_ostream out;
out.push(compressor());
out.push(base64_encoder());
out.push(file_sink("my_file.txt"));
// write to out using std::ostream interface
}


解压过程的调用方式

#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>

namespace io = boost::iostreams;

int main()
{
io::filtering_istream in;
in.push(decompressor());
in.push(base64_decoder());
in.push(file_source("my_file.txt"));
// read from in using std::istream interface
}


这里我不表如何编写filter,大家可以参看iostreams的user manual,写的还是挺详尽的。我想谈谈今天使用iostreams遇到的坑。

我要对某段文本进行RSA加密,RSA算法用的是之前就写好的库,应该不会有问题才对,结果运行时加完密的文件死活解密不了,这怎么可能呢?我反复比对了公私钥对,没有任何错误。同时又单独测了一次RSA算法,也没错,同样的明文加密完还是可以正常解密的。

不知道是不是福尔摩斯说的,排除了一切可能,即使最后一种假设多不可能,那也是真相。折腾了半天,实在没法了,我把程序中RSA加密生成密文和解密时用到的密文比对,居然不一致,差了一位!神奇!再看,是一个0x0a被写成了0x0d 0x0a!

顿时醒悟,这不是对换行符进行了转换吗?艹,谁干的?我生成的文件是binary的,我不要转换什么换行符!

网上查了查,呵呵,原来标准库fstream是会自作聪明地帮我们进行转换换行符,http://blog.sina.com.cn/s/blog_68281ec80100n4jt.html。这位仁兄给出了解决方案,我赶紧试了试

fos.push(FMFileEncryptFilter());
fos.push(file_sink(strFileName.toStdString(), std::ios_base::out | std::ios_base::binary));


没用!哭了!

我怀着万分悲痛的心情,寄希望于在user manual中寻求帮助,于是第一页我就看到了如下两句:

[1]Strictly speaking, it would be better to use a file_descriptor_sink instead of a file_sink here, because file_descriptor_sink never performs code conversion.

[2]Strictly speaking, it would be better to use a file_descriptor_source instead of a file_source here, because file_descriptor_source never performs code conversion.

我滴天,code conversion?难道这就是症结所在吗?赶紧换成如下:

fos.push(FMFileEncryptFilter());    fos.push(file_descriptor_sink(strFileName.toStdString()));


一试,好了!激动之情溢于言表,这个bug我调了快两天了!

虽然我知道没人看,但我还是要写一写,一点一点积累吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  boost