解决zipentry.getsize不可信的方法
原因分析
在日常Java开发中,我们有时会使用到压缩文件,而在读取压缩文件内容时,我们经常使用java.util.zip.ZipFile来获取文件入口,进而使用zipentry.getsize()方法获取文件大小,但这个方法并不总是可靠,有些情况下获取到的文件大小可能是不正确的。
造成这种情况的原因是,zipentry.getsize()方法并没有直接记录文件大小的信息,而是通过解析压缩文件的中央目录来获取文件大小信息。
然而,在某些情况下,压缩文件中的中央目录可能会被破坏或不完整,导致zipentry.getsize()方法无法正确获取文件大小。
解决方案
为了解决这个问题,我们需要使用另一种获取文件大小的方式。
方法一:使用ZipInputStream
我们可以使用java.util.zip.ZipInputStream来读取压缩文件,并使用getnextentry()方法逐个遍历文件入口,然后使用available()方法获取文件大小。
ZipInputStream是从ZipFile派生的流,可以逐个遍历压缩文件中的条目。该流不直接提供文件大小信息,但我们可以通过available()方法的返回值来获取文件大小。
方法二:使用FileChannel
我们也可以使用java.nio.channels.FileChannel来获取压缩文件中特定条目的大小信息。
使用FileChannel并不需要完全读取文件内容,而是可以仅仅获取条目的信息,从而更高效地获取文件大小。
实现代码示例
以下是获取zipentry大小的两种实现方式:
方式一:使用ZipInputStream
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath));
ZipEntry entry;
while((entry = zis.getNextEntry())!=null) {
if(!entry.isDirectory()) {
long size = entry.getSize();
// 如果entry的size小于0,则使用available()获取文件大小
if(size <= 0) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int value = -1;
byte[] buffer = new byte[1024];
while ((value = zis.read(buffer)) != -1) {
bos.write(buffer, 0, value);
}
bos.close();
size = bos.size();
}
}
}
zis.close();
方式二:使用FileChannel
ZipFile zipFile = new ZipFile(zipFilePath);
ZipEntry entry = zipFile.getEntry(fileName);
long size = entry.getSize();
if(size <= 0) {
FileInputStream fis = new FileInputStream(zipFilePath);
FileChannel fc = fis.getChannel();
long start = entry.getOffset();
long end = start + entry.getCompressedSize();
size = fc.map(FileChannel.MapMode.READ_ONLY, start, end).remaining();
fc.close();
fis.close();
}
zipFile.close();
总结
通过以上两种方式,我们能够避免使用ZipEntry.getSize()方法获取到的不准确的文件大小,提高了我们读取压缩文件内容的准确性和效率。