使用ZipOutputStream生成的DOCX文件损坏,macOS无法解压求助
解决ZipOutputStream压缩OfficeOpenXml格式文件夹后解压损坏的问题
你的代码存在几个关键问题,导致生成的Zip文件(DOCX本质是Zip格式)无法被macOS正常解压,尤其是OfficeOpenXml格式对Zip结构的合规性要求更严格:
问题根源
- 未关闭ZipEntry:写入文件内容后没有调用
zipOut.closeEntry()结束当前条目,Zip文件的条目结构不完整,Office工具会判定文件损坏 - 未关闭FileInputStream:文件输入流使用后未关闭,可能导致数据未完全写入,同时造成资源泄漏
- 目录条目未正确标记:处理目录时没有创建带斜杠结尾的ZipEntry,部分解压工具无法识别为目录结构
修复后的完整代码
private const val DEFAULT_BUFFER_SIZE = 1024 * 4 fun zip(source: String?, destination: String?, contentsOnly: Boolean, compression: Int) { try { FileOutputStream(destination).use { fileOut -> ZipOutputStream(fileOut).use { zipOut -> val srcFile = File(source ?: return) // 压缩级别处理 val compressionLevel: Int = when(compression) { 0 -> Deflater.DEFAULT_COMPRESSION 1 -> Deflater.NO_COMPRESSION 2 -> Deflater.BEST_SPEED 3 -> Deflater.BEST_COMPRESSION else -> Deflater.DEFAULT_COMPRESSION } zipOut.setLevel(compressionLevel) zipOut.setMethod(ZipOutputStream.DEFLATED) if (contentsOnly && srcFile.isDirectory) { srcFile.list()?.forEach { fileName -> addToZip("", srcFile.resolve(fileName).absolutePath, zipOut) } } else { addToZip("", srcFile.absolutePath, zipOut) } println("Successfully created $destination") } } } catch (error: Exception) { println("Failed: ${error.message}") error.printStackTrace() } } private fun addToZip(path: String, srcFile: String, zipOut: ZipOutputStream) { val file = File(srcFile) val entryPath = if (path.isEmpty()) { file.name } else { "$path${File.separator}${file.name}" } if (file.isDirectory) { // 创建目录条目,路径以斜杠结尾确保解压工具识别 val dirEntry = ZipEntry("$entryPath${File.separator}") zipOut.putNextEntry(dirEntry) zipOut.closeEntry() file.list()?.forEach { fileName -> addToZip(entryPath, file.resolve(fileName).absolutePath, zipOut) } } else { ZipEntry(entryPath).let { entry -> zipOut.putNextEntry(entry) // 使用use自动关闭输入流 FileInputStream(file).use { inputStream -> val buffer = ByteArray(DEFAULT_BUFFER_SIZE) var len: Int while (inputStream.read(buffer).also { len = it } != -1) { zipOut.write(buffer, 0, len) } } // 必须关闭当前条目,完成条目写入 zipOut.closeEntry() } } }
修复关键点说明
- 自动流管理:使用
use函数自动关闭FileOutputStream、ZipOutputStream和FileInputStream,避免资源泄漏和数据写入不完整 - 关闭ZipEntry:写入文件内容后调用
zipOut.closeEntry(),确保每个Zip条目结构完整 - 目录条目处理:为目录创建带斜杠结尾的ZipEntry,让解压工具正确识别并还原目录结构
- 安全路径拼接:使用
File.resolve()拼接文件路径,避免手动拼接时的错误
内容的提问来源于stack exchange,提问作者Genealogy
相关产品推荐
相关产品推荐

