如何从Java中的7-zip流中提取文件而不将其存储在硬盘上?

时间:2014-02-20 03:07:46

标签: java 7zip compression

我想从7-zip字节流中提取一些文件,它不能存储在硬盘上,所以我不能使用RandomAccessFile类,我已阅读 sevenzipjbinding 源代码,它还使用其他语言写的 lib7-Zip-JBinding.so 等封闭源代码来解压缩文件。官方软件包的方法 SevenZip

SevenZip.Compression.LZMA.Decoder.Code(java.io.InputStream inStream,java.io.OutputStream outStream,long outSize,ICompressProgressInfo progress)

只能解压缩单个文件。

那么如何用纯Java解压缩7-zip字节流?

任何人都有解决方案吗?

抱歉我的英语不好,我在网上等你的回答。

3 个答案:

答案 0 :(得分:11)

Commons compress 1.6及以上版本支持操作7z格式。试试吧。

参考:

http://commons.apache.org/proper/commons-compress/index.html

示例:

    SevenZFile sevenZFile = new SevenZFile(new File("test-documents.7z"));
    SevenZArchiveEntry entry = sevenZFile.getNextEntry();
    while(entry!=null){
        System.out.println(entry.getName());
        FileOutputStream out = new FileOutputStream(entry.getName());
        byte[] content = new byte[(int) entry.getSize()];
        sevenZFile.read(content, 0, content.length);
        out.write(content);
        out.close();
        entry = sevenZFile.getNextEntry();
    }
    sevenZFile.close();

答案 1 :(得分:1)

由于7z解压缩需要随机访问,因此您必须将整个流读入byte[]并使用new SevenZFile(new SeekableInMemoryByteChannel(bytes))。 (如果它长于Integer.MAX_VALUE个字节,则必须创建一个自定义SeekableByteChannel实现。)一旦实例被构造,其过程与SANN3的答案相同。

如果它不适合存储在 中,并且您不能将其写入临时文件,那么7zip由于需要随机访问,因此不是合适的压缩算法。

答案 2 :(得分:0)

代码对我有用:

pom.xml添加:

<!-- Unzip 7z -->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.20</version>
</dependency>
<!-- Unzip 7z dependancy with commons-compress for 7z-->
<!-- https://mvnrepository.com/artifact/org.tukaani/xz -->
<dependency>
    <groupId>org.tukaani</groupId>
    <artifactId>xz</artifactId>
    <version>1.8</version>
</dependency>

添加到课程

public static String unzip(final String directory, final String fileName) {
    final StringBuilder sb = new StringBuilder();
    final File fDirectory = new File(directory);
    final File input7z = new File(fDirectory, fileName);
    try (final SevenZFile sevenZFile = new SevenZFile(input7z)) {
        SevenZArchiveEntry entry = sevenZFile.getNextEntry();
        while (entry != null) {
            LOGGER.info("Treatment of entry : {}", entry.getName());
            try (final FileOutputStream out = new FileOutputStream(new File(fDirectory, entry.getName()))) {
                byte[] content = new byte[(int) entry.getSize()];
                sevenZFile.read(content, 0, content.length);
                out.write(content);
            } catch (final IOException ioe) {
                final String error = "Error when writing entry " + entry.getName();
                LOGGER.error(error);
                sb.append(error).append("\n");
            }
            entry = sevenZFile.getNextEntry();
        }
    } catch (final IOException ioe) {
        final String error = "Error when reading entry " + fileName;
        LOGGER.error(error);
        sb.append(error).append("\n");
    }
    return sb.length() == 0 ? null : sb.toString();
}

更新:

无商店:

public static String getContentOneFile(final String directory, final String fileName) throws IOException {
    final List<String> subFilenames = ls(directory, fileName);
    if (subFilenames.size() == 1) {
        return getContent(directory, fileName, subFilenames.get(0));
    } else if (subFilenames.size() == 0) {
        throw new IOException("No file found in 7zip : " + directory + ":" + fileName);
    } else {
        throw new IOException("Can not extract data from many document. Please specify subFilename in " + subFilenames);
    }
}

使用ls方法:

    public static List<String> ls(final String directory, final String fileName) throws IOException {
        final List<String> out = new ArrayList<>();
        final File fDirectory = new File(directory);
        final File input7z = new File(fDirectory, fileName);
        try (final SevenZFile sevenZFile = new SevenZFile(input7z)) {
            SevenZArchiveEntry entry = sevenZFile.getNextEntry();
            while (entry != null) {
                out.add(entry.getName());
                entry = sevenZFile.getNextEntry();
            }
        } catch (final IOException ioe) {
            final String error = "Error when reading entry " + fileName;
            LOGGER.error(error);
            throw ioe;
        }
        return out;
    }

并使用getContent方法:

   public static String getContent(final String directory, final String fileName, final String subFileName) throws IOException {
        String out = null;
        final File fDirectory = new File(directory);
        final File input7z = new File(fDirectory, fileName);
        try (final SevenZFile sevenZFile = new SevenZFile(input7z)) {
            SevenZArchiveEntry entry = sevenZFile.getNextEntry();
            while (entry != null) {
                LOGGER.info("Treatment of entry : {}", entry.getName());
                if (subFileName.equals(entry.getName())) {
                    byte[] content = new byte[(int) entry.getSize()];
                    sevenZFile.read(content, 0, content.length);
                    out = new String(content);
                }
                entry = sevenZFile.getNextEntry();
            }
        } catch (final IOException ioe) {
            final String error = "Error when reading entry " + fileName;
            LOGGER.error(error);
            throw ioe;
        }
        return out;
    }