如何不使用ByteArrayOutputStream从ZipEntry中获取字节并简化代码
回答
一、简化现有代码
你可以利用Java 9及以上版本提供的InputStream.readAllBytes()方法,直接读取ZipEntry对应的全部字节,省去手动循环写入ByteArrayOutputStream的步骤,代码会简洁很多:
public UnzippedFile unzip(ZipFile zipFile) throws IOException { var unzippedFile = new UnzippedFile(); try (ZipInputStream zipInputStream = ZipUtils.toZipInputStream(zipFile)) { ZipEntry entry; while ((entry = zipInputStream.getNextEntry()) != null) { // 直接读取当前entry的全部字节 byte[] entryBytes = zipInputStream.readAllBytes(); unzippedFile.addFileToMap(entry.getName(), entryBytes); zipInputStream.closeEntry(); // 显式关闭entry,确保资源释放 } } return unzippedFile; }
如果你的环境是Java 8,也可以封装一个工具方法来替代readAllBytes(),避免重复写循环逻辑:
private static byte[] readAllBytes(InputStream in) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } return out.toByteArray(); }
之后在主方法里调用这个工具方法,代码结构会更整洁。
二、不使用ByteArrayOutputStream的实现方式
除了上述readAllBytes()(JDK原生实现内部虽类似ByteArrayOutputStream逻辑,但上层无需显式编写),如果要完全手动实现不依赖它的逻辑,可以先获取ZipEntry的大小,预先分配对应长度的字节数组再读取:
public UnzippedFile unzip(ZipFile zipFile) throws IOException { var unzippedFile = new UnzippedFile(); try (ZipInputStream zipInputStream = ZipUtils.toZipInputStream(zipFile)) { ZipEntry entry; while ((entry = zipInputStream.getNextEntry()) != null) { long entrySize = entry.getSize(); if (entrySize == -1) { // 无法获取entry大小,降级到readAllBytes方式 byte[] entryBytes = zipInputStream.readAllBytes(); unzippedFile.addFileToMap(entry.getName(), entryBytes); } else { // 预先分配对应大小的字节数组 byte[] entryBytes = new byte[(int) entrySize]; int totalRead = 0; int readLen; while (totalRead < entrySize && (readLen = zipInputStream.read(entryBytes, totalRead, (int) entrySize - totalRead)) != -1) { totalRead += readLen; } unzippedFile.addFileToMap(entry.getName(), entryBytes); } zipInputStream.closeEntry(); } } return unzippedFile; }
注意:entry.getSize()可能返回-1(比如压缩文件使用了无法预知压缩后大小的算法,或者entry是目录),这种情况需要做兼容处理,降级到通用读取方式。
另外,若使用第三方库如Apache Commons IO的IOUtils.toByteArray(InputStream),也能避免自己编写ByteArrayOutputStream相关逻辑,但这需要引入外部依赖,可根据项目需求选择。
内容的提问来源于stack exchange,提问作者BugsOverflow
相关产品推荐
相关产品推荐

