简体   繁体   English

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

[英]how to extract files from a 7-zip stream in Java without store it on hard disk?

I want to extract some files from a 7-zip byte stream,it can't be stored on hard disk,so I can't use RandomAccessFile class,I have read sevenzipjbinding source code,it also uncompresses the file with some closed source things like lib7-Zip-JBinding.so which wrote by other language.And the method of the official package SevenZip我想从一个 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)

can only uncompress a single file.只能解压缩单个文件。

So how could I uncompress a 7-zip byte stream with pure Java?那么我怎么能用纯 Java 解压缩一个 7-zip 字节流呢?

Any guys have solution?有大佬有解决办法吗?

Sorry for my poor English and I'm waiting for your answers online.抱歉我的英语不好,我在网上等你的答案。

Commons compress 1.6 and above has support for manipulating 7z format. Commons compress 1.6 及以上版本支持操作 7z 格式。 Try it.尝试一下。

Reference :参考 :

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

Sample :样本 :

    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();

Since 7z decompression requires random access, you'll have to read the whole stream into a byte[] and use new SevenZFile(new SeekableInMemoryByteChannel(bytes)) .由于 7z 解压需要随机访问,您必须将整个流读入byte[]并使用new SevenZFile(new SeekableInMemoryByteChannel(bytes)) (If it's longer than Integer.MAX_VALUE bytes, you'll have to create a custom SeekableByteChannel implementation.) Once the instance is constructed, the process is the same as in SANN3's answer. (如果它长于Integer.MAX_VALUE字节,则必须创建自定义SeekableByteChannel实现。)构造实例后,该过程与 SANN3 的答案相同。

If it won't fit in memory and you can't write it to a temporary file, then 7zip isn't a suitable compression algorithm given its need for random access.如果它不适合内存并且您无法将其写入临时文件,那么 7zip 就不是一种合适的压缩算法,因为它需要随机访问。

Code working for me :为我工作的代码:

pom.xml to add :要添加的 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>

Add to class添加到班级

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();
}

UPDATE :更新 :

Without store :没有商店:

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);
    }
}

With ls method :使用 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;
    }

And with getContent method :并使用 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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM