我正在尝试使用boost :: iostreams压缩数据。
copy()的文档说它的两个参数最后通过调用它们的模板函数close()来关闭。我的测试代码是:
#include <iostream>
#include <fstream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
using namespace std;
int main(void)
{
ifstream ifs("output", ios::binary);
ofstream ofs("output.boost.gz", ios::binary);
boost::iostreams::filtering_streambuf<boost::iostreams::output> out;
out.push(boost::iostreams::gzip_compressor());
out.push(ofs);
cout << (ifs.is_open() ? "ifs is opened" : "ifs not opened") << endl;
cout << (ofs.is_open() ? "ofs is opened" : "ofs not opened") << endl;
boost::iostreams::copy(ifs, out);
cout << (ifs.is_open() ? "ifs is opened" : "ifs not opened") << endl;
cout << (ofs.is_open() ? "ofs is opened" : "ofs not opened") << endl;
return 0;
}
此测试输出:
ifs is opened
ofs is opened
ifs not opened
ofs is opened
你可以看到仍然打开了.s我的问题是:为什么? boost :: iostreams :: close()在传递filtering_streambuf对象时做了什么?
答案 0 :(得分:4)
有趣。
走下兔子洞 [1] ,结果发现最终到达了close_impl<any_tag>
,因为ofstream包裹在filtering_streambuf里面的chain_buf深处。实现如下:
template<>
struct close_impl<any_tag> {
template<typename T>
static void close(T& t, BOOST_IOS::openmode which)
{
if (which == BOOST_IOS::out)
iostreams::flush(t);
}
template<typename T, typename Sink>
static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
{
if (which == BOOST_IOS::out) {
non_blocking_adapter<Sink> nb(snk);
iostreams::flush(t, nb);
}
}
};
因此,正如您所看到的,记录的行为实际上只是刷新了链接的输出流缓冲区(在该调用之前,包含的实体上也存在同步,IIRC) 。
我完全同意这可以更加明确。
阅读决定专业化的TMP代码:
template<typename T>
struct close_tag {
typedef typename category_of<T>::type category;
typedef typename detail::unwrapped_type<T>::type unwrapped;
typedef typename
iostreams::select<
mpl::not_< is_convertible<category, closable_tag> >,
any_tag,
mpl::or_<
is_boost_stream<unwrapped>,
is_boost_stream_buffer<unwrapped>
>,
close_boost_stream,
mpl::or_<
is_filtering_stream<unwrapped>,
is_filtering_streambuf<unwrapped>
>,
close_filtering_stream,
mpl::or_<
is_convertible<category, two_sequence>,
is_convertible<category, dual_use>
>,
two_sequence,
else_,
closable_tag
>::type type;
};
我想到了几种解决方法:
为close_tag<>
定义一个std::ofstream
的特化,它实际上会返回一个不同的标记,并使其关闭(我建议不要这样做,因为它可能会产生意想不到的影响由Boost Iostreams开发者持有的假设)
为输出流使用boost类:
#include <iostream>
#include <fstream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/gzip.hpp>
using namespace std;
int main(void)
{
cout << boolalpha;
ifstream ifs("output", ios::binary);
boost::iostreams::file_sink ofile("output.boost.gz");
boost::iostreams::filtering_streambuf<boost::iostreams::output> out;
out.set_auto_close(true);
out.push(boost::iostreams::gzip_compressor());
out.push(ofile);
cout << "out.is_complete(): " << out.is_complete() << endl;
cout << "ifs.is_open()? " << ifs.is_open() << endl;
cout << "ofile.is_open()? " << ofile.is_open() << endl;
boost::iostreams::copy(ifs, out);
cout << "out.is_complete(): " << out.is_complete() << endl;
cout << "ifs.is_open()? " << ifs.is_open() << endl;
cout << "ofile.is_open()? " << ofile.is_open() << endl;
}
[1] 这是一个非常大的兔子洞,我必须补充一下。我想知道所有这些通用性真正有什么好处