java - 在java中使用apache common compress/org.tukaani.xz,解码LZMA compress zip文件的问题

getting org.tukaani.xz.UnsupportedOptionsException : Uncompressed size is too big error while trying to decode LZMA compress xls file. 而非LZMA文件得到解包/解码没有问题,

我在使用Apache commons compress和org.tukaani.xz。

参考示例代码


package com.concept.utilities.zip;



import java.io.File;


import java.io.IOException;


import java.io.InputStream;



import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;


import org.apache.commons.compress.archivers.zip.ZipFile;


import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;



public class ApacheComm {



 public void extractLZMAZip(File zipFile, String compressFileName, String destFolder) {



 ZipFile zip = null;


 try {



 zip = new ZipFile(zipFile);


 ZipArchiveEntry zipArchiveEntry = zip.getEntry(compressFileName);


 if (null != zipArchiveEntry) {


 String name = zipArchiveEntry.getName();



 // InputStream is = zip.getInputStream(zipArchiveEntry);


 InputStream israw = zip.getRawInputStream(zipArchiveEntry);



 LZMACompressorInputStream lzma = new LZMACompressorInputStream(israw);


 }



 } catch (IOException e) {


 e.printStackTrace();


 } finally {


 if (null != zip)


 ZipFile.closeQuietly(zip);


 }


 }



 public static void main(String[] args) throws IOException {



 ApacheComm c = new ApacheComm();


 try {


 c.extractLZMAZip(new File("H:archivesrollLZMA.zip"),"roll.xls","H:archives");


 } catch (Exception e) {


 e.printStackTrace();


 }



 }



}



错误


org.tukaani.xz.UnsupportedOptionsException: Uncompressed size is too big


 at org.tukaani.xz.LZMAInputStream.initialize(Unknown Source)


 at org.tukaani.xz.LZMAInputStream.<init>(Unknown Source)


 at org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream.<init>(LZMACompressorInputStream.java:50)


 at com.concept.utilities.zip.ApacheComm.extractLZMAZip(ApacheComm.java:209)


 at com.concept.utilities.zip.ApacheComm.main(ApacheComm.java:224)



有没有其他方法可以LZMA解码zip文件

时间:

你的代码无法工作的原因在于,LZMA压缩数据段的标头与普通压缩的LZMA文件不同。

你可以阅读https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT (4.4.4 general purpose bit flag, 5.8 LZMA - Method 14 )的规范,引用重要的部分:

5.8.5 [...] the LZMA Compressed Data Segment will consist of an LZMA Properties Header followed by the LZMA Compressed Data as shown :


[LZMA properties header for file 1]


[LZMA compressed data for file 1]



[... ]

5.8.8 LZMA属性标头中属性信息的存储字段如下所示:


LZMA Version Information 2 bytes


LZMA Properties Size 2 bytes


LZMA Properties Data variable, defined by"LZMA Properties Size"



5.8.8.1 LZMA版本信息-此字段标识用于压缩文件的LZMA SDK版本,

代码示例:


import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;


import org.apache.commons.compress.archivers.zip.ZipFile;


import org.apache.commons.compress.archivers.zip.ZipMethod;


import org.apache.commons.io.IOUtils;


import org.tukaani.xz.LZMAInputStream;



import java.io.IOException;


import java.io.InputStream;


import java.nio.ByteBuffer;


import java.nio.ByteOrder;



public class ApacheComm


{


 public InputStream getInputstreamForEntry(ZipFile zipFile, ZipArchiveEntry ze) throws IOException


 {


 if (zipFile.canReadEntryData(ze))


 {


 return zipFile.getInputStream(ze);


 } else if (ze.getMethod() == ZipMethod.LZMA.getCode()) {


 InputStream inputStream = zipFile.getRawInputStream(ze);


 ByteBuffer buffer = ByteBuffer.wrap(IOUtils.readFully(inputStream, 9))


 .order(ByteOrder.LITTLE_ENDIAN);



 // Lzma sdk version used to compress this data


 int majorVersion = buffer.get();


 int minorVersion = buffer.get();



 // Byte count of the following data represent as an unsigned short.


 // Should be = 5 (propByte + dictSize) in all versions


 int size = buffer.getShort() & 0xffff;


 if (size != 5)


 throw new UnsupportedOperationException();



 byte propByte = buffer.get();



 // Dictionary size is an unsigned 32-bit little endian integer.


 int dictSize = buffer.getInt();



 long uncompressedSize;


 if ((ze.getRawFlag() & (1 << 1)) != 0)


 {


 // If the entry uses EOS marker, use -1 to indicate


 uncompressedSize = -1;


 } else {


 uncompressedSize = ze.getSize();


 }



 return new LZMAInputStream(inputStream, uncompressedSize, propByte, dictSize);


 } else {


 throw new UnsupportedOperationException();


 }


 }


}



...