C++ Boost 和 Lzma 解压缩

5

我正在尝试使用boost库1.67.0在Linux平台上解压缩.7z(或.xz或.lzma)文件,代码如下:

    vector<T> readFromCompressedFile(string input_file_path, string output_file_path)
    {
    namespace io = boost::iostreams;

    stringstream strstream;

    ifstream file(input_file_path.c_str(), ios_base::in | ios_base::binary);
    ofstream out(output_file_path, ios_base::out | ios_base::binary);

    boost::iostreams::filtering_istream in;
    in.push(io::lzma_decompressor());
    in.push(file);

    io::copy(in, out);

    cout<<strstream.str()<<endl;

代码编译成功,但在复制方法中出现运行时异常(lzma_error)。
warning: GDB: Failed to set controlling terminal: Operation not permitted
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::iostreams::lzma_error> >'
  what():  lzma error: iostream error

我尝试使用filtering_streambuf过滤器,但运气不佳。这段代码与gzip示例非常相似。

https://www.boost.org/doc/libs/1_67_0/libs/iostreams/doc/classes/gzip.html#examples

然而,我能够使用上述代码解压缩使用gzip压缩的文件。似乎问题仅限于LZMA算法。

有相同问题的人吗?有任何想法吗?

谢谢

2个回答

5

您的代码没有问题,这不是一个bug。

起初,我遇到了与上述描述相同的问题,但经过一些研究,我发现这是因为boost iostreams库调用了由XZ库提供的lzma_stream_decoder来执行解码工作,而lzma_stream_decoder不支持.lzma或.7z格式文件。如果您尝试使用boost iostreams库解码.lzma或.7z格式文件,将会抛出一个带有错误代码LZMA_FORMAT_ERROR的异常。请参考XZ源代码中的错误代码定义xz-5.2.4.tar.gz

\src\liblzma\api\lzma\base.h

LZMA_FORMAT_ERROR       = 7,
    /**<
     * \brief       File format not recognized
     *
     * The decoder did not recognize the input as supported file
     * format. This error can occur, for example, when trying to
     * decode .lzma format file with lzma_stream_decoder,
     * because lzma_stream_decoder accepts only the .xz format.
     */

请参考boost iostreams库的源代码:lzma.cpp 您可以尝试解码一个.xz文件,不会有任何问题。我已经在Windows X64和boost库1.66.0上使用了您提供的相同代码进行了测试。
顺便说一下,@sehe提供的用于错误检测的代码是误导性的:
 try {
    io::copy(in, out);
} catch(io::lzma_error const& e) {
    std::cout << boost::diagnostic_information(e, true);
    std::cout << e.code() << ": " << e.code().message() << "\n";
}

should be:

 try {
    io::copy(in, out);
} catch(io::lzma_error const& e) {
    std::cout << boost::diagnostic_information(e, true);
    std::cout << e.error() << ": " << e.code().message() << "\n";
}

然后你会发现抛出异常的错误代码是:7(LZMA_FORMAT_ERROR)。


非常感谢 - 这不仅是扩展名的问题,而且 xzlzma 是不同的压缩格式。 - TCSGrad

3

我可以确认出现了同样的问题。

使用其他工具解压lzma文件没有问题。可能存在版本问题,或者可能是个bug。这里有一份精简过的代码,去掉了一些噪音,修正了有问题的风格(using namespace std),并尝试获得更多的错误信息:

#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/lzma.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <fstream>
#include <iostream>

namespace io = boost::iostreams;

void foo(std::string input_file_path, std::string output_file_path) {
    namespace io = boost::iostreams;

    std::ifstream file(input_file_path, std::ios::binary);
    std::ofstream out(output_file_path, std::ios::binary);

    boost::iostreams::filtering_istreambuf in;
    in.push(io::lzma_decompressor());
    in.push(file);

    try {
        io::copy(in, out);
    } catch(io::lzma_error const& e) {
        std::cout << boost::diagnostic_information(e, true);
        std::cout << e.code() << ": " << e.code().message() << "\n";
    } catch(boost::exception const& e) {
        std::cout << boost::diagnostic_information(e, true);
    }
}

int main() {
    foo("test.cpp.lzma", "output.txt");
}

在我的系统上,我已经验证了测试程序和 /usr/bin/lzma 链接到完全相同版本的库,因此版本问题在这一点上似乎相当不可能:

enter image description here

我认为这个问题应该向上游报告(在boost Trac,邮件列表或github issue中),


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接