Java中ZipEntry无法向嵌套Zip内目录写入文件的问题咨询
问题描述
期望生成的Zip结构如下:
parent.zip - testDirectory/ - testZip.zip
将文件读入byte[]后写入testDirectory目录时,目录始终为空;但将同一个byte[]写入testZip.zip压缩包时,文件能被正确保存。parent.zip、testDirectory/和testZip.zip均能正常创建,且无任何异常抛出。
问题原因
你错误地将完整的Zip格式字节流直接写入了目录条目。根据Zip规范,目录条目仅作为标记存在,不需要写入任何内容;若要在testDirectory下存放文件,需要为每个文件创建以testDirectory/为前缀的ZipEntry,而非把整个Zip字节流写入目录条目。
当前代码中,getMediaFiles()返回的是包含test.txt的完整Zip字节流,将其写入testDirectory/目录条目不符合Zip规范,因此解压后目录为空。而写入testZip.zip时,因为它是文件条目,Zip字节流会被当作普通文件内容保存,所以能得到正确的Zip文件。
解决方案
根据需求不同,有两种修正方式:
方式一:直接构建目录下的文件(推荐)
如果是从头构建testDirectory的内容,无需先打包成Zip,直接在父Zip流中创建带目录前缀的文件条目即可:
private static void addFiles(ZipOutputStream zos) throws Exception { // 直接写入testDirectory下的test.txt文件 byte[] fileContent = "Hello World".getBytes(); // 可选:显式创建目录条目(部分解压工具会自动创建不存在的目录) ZipEntry dirEntry = new ZipEntry("1" + File.separator + "testDirectory/"); zos.putNextEntry(dirEntry); zos.closeEntry(); // 创建目录下的文件条目 ZipEntry fileEntry = new ZipEntry("1" + File.separator + "testDirectory/test.txt"); fileEntry.setSize(fileContent.length); zos.putNextEntry(fileEntry); zos.write(fileContent); zos.closeEntry(); // 保留testZip.zip的写入逻辑(这部分是正确的) byte[] mediaZip = getMediaFiles(); ZipEntry zipEntry = new ZipEntry("1" + File.separator + "testZip.zip"); zipEntry.setSize(mediaZip.length); zos.putNextEntry(zipEntry); zos.write(mediaZip); zos.closeEntry(); } // getMediaFiles方法保持不变 private static byte[] getMediaFiles() throws Exception { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(baos)) { byte[] bytes = "Hello World".getBytes(); String entryName = "test.txt"; ZipEntry entry = new ZipEntry(entryName); entry.setSize(bytes.length); zos.putNextEntry(entry); zos.write(bytes); zos.closeEntry(); zos.close(); return baos.toByteArray(); } }
方式二:展开已有Zip到目标目录
如果需要将已有Zip文件的内容展开到testDirectory下,需先解析Zip字节流,再逐个条目添加目录前缀后写入父Zip流:
private static void addFiles(ZipOutputStream zos) throws Exception { byte[] mediaZipBytes = getMediaFiles(); // 解析已有Zip字节流,将内容展开到testDirectory下 try (ByteArrayInputStream bais = new ByteArrayInputStream(mediaZipBytes); ZipInputStream zis = new ZipInputStream(bais)) { ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { // 为每个条目添加testDirectory前缀 String newEntryName = "1" + File.separator + "testDirectory/" + entry.getName(); ZipEntry newEntry = new ZipEntry(newEntryName); newEntry.setSize(entry.getSize()); zos.putNextEntry(newEntry); // 复制文件内容到父Zip流 byte[] buffer = new byte[1024]; int len; while ((len = zis.read(buffer)) != -1) { zos.write(buffer, 0, len); } zos.closeEntry(); zis.closeEntry(); } } // 保留testZip.zip的写入逻辑 ZipEntry zipEntry = new ZipEntry("1" + File.separator + "testZip.zip"); zipEntry.setSize(mediaZipBytes.length); zos.putNextEntry(zipEntry); zos.write(mediaZipBytes); zos.closeEntry(); } // getMediaFiles方法保持不变 private static byte[] getMediaFiles() throws Exception { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(baos)) { byte[] bytes = "Hello World".getBytes(); String entryName = "test.txt"; ZipEntry entry = new ZipEntry(entryName); entry.setSize(bytes.length); zos.putNextEntry(entry); zos.write(bytes); zos.closeEntry(); zos.close(); return baos.toByteArray(); } }
内容的提问来源于stack exchange,提问作者Angry Red Panda
相关产品推荐
相关产品推荐

