Java中波斯语文件名压缩为Zip后显示问号的问题求助
解决Java压缩Zip时波斯语文件名变"?"的问题
我来帮你搞定这个问题——之前处理过不少非ASCII文件名的Zip压缩场景,太清楚这里的坑了!
首先说核心原因:Java标准库的ZipOutputStream默认用的是CP437编码,这是传统Zip格式的老标准,根本不支持波斯语这类非拉丁字符,所以你的文件名里的波斯语字符会被直接替换成"?"。另外你用URLEncoder处理文件名是走偏了——那玩意儿是给URL编码用的,和Zip文件名半毛钱关系都没有,不抛异常才怪呢!
下面给你两个靠谱的解决方案:
方案1:用Java 7+原生API设置UTF-8编码
从Java 7开始,ZipOutputStream新增了setEncoding()方法,直接指定用UTF-8编码文件名就行,不用额外折腾第三方库。
给你写个完整的示例代码,直接就能跑:
import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class PersianZipHandler { public static void main(String[] args) throws IOException { // 你的波斯语文件名 String sourceFilePath = "تست.txt"; String outputZipPath = "波斯语文件压缩包.zip"; // 用try-with-resources自动关闭流,避免资源泄漏 try (FileOutputStream fos = new FileOutputStream(outputZipPath); ZipOutputStream zipOut = new ZipOutputStream(fos)) { // 关键!设置Zip使用UTF-8编码文件名 zipOut.setEncoding("UTF-8"); File targetFile = new File(sourceFilePath); try (FileInputStream fis = new FileInputStream(targetFile)) { ZipEntry zipEntry = new ZipEntry(targetFile.getName()); zipOut.putNextEntry(zipEntry); // 读写文件内容 byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { zipOut.write(buffer, 0, bytesRead); } zipOut.closeEntry(); } } } }
方案2:用Apache Commons Compress库(更稳定兼容)
如果你的项目可以引入第三方库,我更推荐用Apache Commons Compress——它对Zip格式的支持比原生API更全面,尤其是处理非ASCII文件名时兼容性更好,还支持Zip64这类扩展格式。
首先在Maven里加依赖(Gradle的话对应调整就行):
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version>1.24.0</version> </dependency>
然后是示例代码:
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import java.io.*; public class CommonsCompressZipDemo { public static void main(String[] args) throws IOException { String sourceFilePath = "تست.txt"; String outputZipPath = "commons-波斯语压缩包.zip"; try (FileOutputStream fos = new FileOutputStream(outputZipPath); ZipArchiveOutputStream zipOut = new ZipArchiveOutputStream(fos)) { // 显式开启UTF-8文件名支持,确保兼容性 zipOut.setUseLanguageEncodingFlag(true); zipOut.setCreateUnicodeExtraFields(ZipArchiveOutputStream.UnicodeExtraFieldPolicy.NOT_ENCODEABLE); File targetFile = new File(sourceFilePath); ZipArchiveEntry entry = new ZipArchiveEntry(targetFile, targetFile.getName()); zipOut.putArchiveEntry(entry); try (FileInputStream fis = new FileInputStream(targetFile)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { zipOut.write(buffer, 0, bytesRead); } } zipOut.closeArchiveEntry(); } } }
最后再强调下:别用URLEncoder处理Zip文件名!那是用来转URL参数的,比如把空格转成%20,和Zip文件名编码完全不是一回事,用它只会添乱,导致异常。
内容的提问来源于stack exchange,提问作者Amir Amiri
相关产品推荐
相关产品推荐

