0

我有一些数据要格式化和输出,可以是原始文本文件,也可以是 .gz 压缩文本文件。

因此,我想做这样的事情:

shared_ptr<ofstream> file = make_shared<ofstream>(filename.c_str());
shared_ptr<ostream> stream;
if (compressed) {
    stream = getCompressedStream(*file);
} else {
    stream = std::move(file);
}

for (auto c = data.begin(); c != data.end(); ++c) {
    *stream << **c << "\t" << (*c)->getThing() << endl;
}

使用 getCompressedStream 解密流并返回新的非加密流的函数:

std::unique_ptr<std::ostream> getCompressedStream(std::ofstream& file)
{
    typedef io::filtering_ostream filter;
    std::unique_ptr<filter> out = std::unique_ptr<filter> (new filter());
    out->push(io::gzip_compressor());
    out->push(file);
    return std::move(out);
}

所以我希望 getCompressedStream 抽象调用 boost lib,这样我就只在我的主程序中使用 std 流。

它不起作用:.gz 文件已损坏/不可读。

根据这个线程,过滤流的输出是在对象的销毁中完成的。因此,我不知道它是否可以用 shared_ptr 干净地完成。我不知道文件或流是否首先被破坏,我想这会导致问题。

您认为以这种方式实现 getCompressedStream 可行吗?你会改变什么?

谢谢

编辑:如果我切换到常规指针而不是共享指针,它会起作用,并在文件之前明确删除流。

4

1 回答 1

0

我不确定。真正的问题是您从未明确关闭ofstream,因此您不知道发生了什么。(除非在例外情况下,无论如何您都将删除新文件,您必须 在关闭ofstream检查对象的状态,以了解一切是否成功。)更一般地说,您的解决方案似乎过于复杂我; 你试图在一个函数中做太多事情。我通常这样做的方式(使用我自己的过滤streambuf,比boost版本早几年)是做类似的事情:

std::ofstream file( filename.c_str() );
if ( compressed ) {
    CompressedStreambuf c( file );
    outputData( file );
} else {
    outputDate( file );
}
file.close();
if ( !file ) {
    remove( filename.c_str() );   //  Since it isn't complete
    //  Ensure that program return code is failure.
}

当然,我自己的过滤流缓冲区的工作方式与 boost 的工作方式略有不同:构造函数ostream将过滤器插入到 前面ostream,而析构函数则刷新并删除过滤器(RAII 的一种变体)。但是制作 Boost 类的包装器来支持这一点应该不会太难。

这种解决方案的优点是保证一切都以正确的嵌套顺序构造和破坏,因为没有允许任意顺序的动态分配。

于 2013-08-13T11:52:20.953 回答