驭风万里无垠

STL Binary Stream 和 Container 数据交互的小细节

偶然发现一个用了STL很久都没有发现的问题,特记之。


事情的起因很简单,需要做一些简单的重构,将原来读文件得到二进制缓冲数据的部分分离开,拉一个单独的API,接收文件二进制内容的缓冲区参数;估计很多人都会做这样的事情,将一个小程序变得更有用,不得不把300行的main拆开来,露几个函数来用。

其他的部分都如想象般的简单,唯独在测试原有读文件调用新接口的地方卡住了。
原来的逻辑如此这般:

FILE* fin = open("file.bin", "rb");
if (fin == NULL)
{
    exit(-1);
}

unsigned char buf[65536] = {0};
char ch;
int i = 0;
while ( (ch = fgetc(fin)) != EOF)
{
    buf[i++] = ch;
    if (i >= sizeof(buf))
        exit(-2);
}

//..................
改写后的调用接口如下:
typedef std::vector<unsigned char> BinaryBufferType;
int SomeFunc(BinaryBufferType& buf, ...)

 

为了完成接口测试并且还原原有功能,需要将文件内容读入到一个vector中来测试。初始的想法如下:

ifstream ifs("file.bin", ios::in|ios::binary);
if (!ifs.good())
{
    exit(-1);
}

typedef std::istream_iterator<char> FsIt;
BinaryBufferType buf;
std::copy(FsIt(ifs), FsIt(), std::back_inserter(buf));

 

除了出错检查,重要的部分就是一个copy调用将STL流的内容自动拷贝到vector里边;这是一个很典型的例子,乃至SGI的文档里边关于copy算法的例子就是这样的。

问题是,这个代码却是有问题的,和上边的C代码并不等价,实际测试的过程中,发现居然漏掉了3个Byte的数据。

顿时感觉很奇怪了,马上GDB跟了下,由于数据太多,一下子没看出来那个出书丢了(后来发现是0c);想想是否与binary方式有关呢,已经采用binary方式读入了呀?

 

Google一番才发现有人遇到了同样的问题,原来 stream_iterator 默认采用的是formatted I/O方式处理数据,所以某些东西会被跳过。

如果需要拷贝二进制数据,该采用如下的法子:

typedef std::istreambuf_iterator<char> FsIt;
BinaryBufferType buf;
std::copy(FsIt(buf.rdbuf()), FsIt(), std::back_inserter(buf));
 
就是这点小小的差别,以前一直被忽略了…… 浪费了不少时间,当时如果搜索istreambuf_iterator,似乎能发现Effective STL里边讲述过这个,可惜当时看的时候,很快过去,
居然一点印象都没有?
真是“绝知此事要躬行”了。

 

posted on 2009-08-27 21:09 skyscribe 阅读(585) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


<2009年8月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

导航

统计

常用链接

留言簿(3)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜