java 压缩包 文件名乱码问题解决

本文深入探讨了文件压缩与解压缩的核心算法,包括如何使用ZipOutputStream进行文件压缩,以及如何通过ZipFile实现文件解压。重点介绍了参数设置、递归压缩、输出空目录等功能,并提供了实际应用示例。
搞半天了,终于在网上找到了这个解决方法。
压缩代码

/**
* @param path
* 要压缩的路径, 可以是目录, 也可以是文件.
* @param basePath
* 如果path是目录,它一般为new File(path), 作用是:使输出的zip文件以此目录为根目录,
* 如果为null它只压缩文件, 不解压目录.
* @param zo
* 压缩输出流
* @param isRecursive
* 是否递归
* @param isOutBlankDir
* 是否输出空目录, 要使输出空目录为true,同时baseFile不为null.
* @throws IOException
*/
public static void zip(String path, File basePath, ZipOutputStream zo,
boolean isRecursive, boolean isOutBlankDir) throws IOException {

File inFile = new File(path);

File[] files = new File[0];
if (inFile.isDirectory()) { // 是目录
files = inFile.listFiles();
} else if (inFile.isFile()) { // 是文件
files = new File[1];
files[0] = inFile;
}
byte[] buf = new byte[1024];
int len;
// System.out.println("baseFile: "+baseFile.getPath());
for (int i = 0; i < files.length; i++) {
String pathName = "";
if (basePath != null) {
if (basePath.isDirectory()) {
pathName = files[i].getPath().substring(
basePath.getPath().length() + 1);
} else {// 文件
pathName = files[i].getPath().substring(
basePath.getParent().length() + 1);
}
} else {
pathName = files[i].getName();
}
if (files[i].isDirectory()) {
if (isOutBlankDir && basePath != null) {
zo.putNextEntry(new ZipEntry(pathName + "/")); // 可以使空目录也放进去
}
if (isRecursive) { // 递归
zip(files[i].getPath(), basePath, zo, isRecursive,
isOutBlankDir);
}
} else {
FileInputStream fin = new FileInputStream(files[i]);
zo.putNextEntry(new ZipEntry(pathName));
while ((len = fin.read(buf)) > 0) {
zo.write(buf, 0, len);
}
fin.close();
}
}
inFile = null;
files = null;
}

/**
*
* 压缩电子文件为ZIP包
*
* @param directory
* 需要压缩的目录
* @param zipFileName
* ZIP压缩文件完整路径名
* @return
*/
public static boolean expZip(String directory, String zipFileName) {
boolean bool = false;
try {
File file = new File(directory);
boolean validate = zipFileName.toLowerCase().endsWith(".zip");
if (!file.exists() || !validate || !file.isDirectory()) {
return false;
} else {

directory = directory.replace(File.separatorChar, '/');
zipFileName = zipFileName.replace(File.separatorChar, '/');
int x = zipFileName.lastIndexOf("/");
if (x <= -1) {
return false;
} else {
String zipdir = zipFileName.substring(0, x);
File zipdirs = new File(zipdir);
zipdirs.mkdirs();
zipdirs = null;
}

OutputStream os = new FileOutputStream(zipFileName);
BufferedOutputStream bs = new BufferedOutputStream(os);
ZipOutputStream zo = new ZipOutputStream(bs);
//[color=red]些句相当重要[/color]
zo.setEncoding(System.getProperty("sun.jnu.encoding"));
ZipOption.zip(directory, new File(directory), zo, true, true);
zo.closeEntry();
zo.close();
bs.close();
os.close();

File exit = new File(zipFileName);
bool = exit.exists();
exit = null;
}
file = null;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

return bool;
}

解压缩代码

/**
* 解压ZIP文件
*
* @param zipFileName
* String 为需要解压的zip文件
* @param extPlace
* String 为解压后文件的存放路径
*/
public static void extZipFileList(String zipFileName, String extPlace)
throws Exception {
// 验证ZIP压缩文件是否有效
File fileZip = new File(zipFileName);
boolean exists = fileZip.exists();// 判断文件/文件夹是否存在
if (exists) {
// 创建extPlace目录
File dirs = new File(extPlace);
dirs.mkdirs();
dirs = null;
// 请空目录
ZipFile zipFile = null;
try {
//[color=red]些句相当重要[/color]
System.setProperty("sun.zip.encoding",System.getProperty("sun.jnu.encoding"));
zipFile = new ZipFile(zipFileName);
FileInputStream zin = new FileInputStream(zipFileName);
ZipInputStream zis = new ZipInputStream(zin);
//这里必需用jdk自带的ZipEntry
java.util.zip.ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
String entryName = zipEntry.getName().replace(
File.separatorChar, '/');
String names[] = entryName.split("/");
int length = names.length;
String path = extPlace;
for (int v = 0; v < length; v++) {
if (v < length - 1) {
path += names[v] + "/";
new File(path).mkdir();
} else { // 最后一个
if (entryName.endsWith("/")) { // 为目录,则创建文件夹
new File(extPlace + entryName).mkdir();
} else {
FileOutputStream fos = new FileOutputStream(
extPlace + entryName);
int len;
byte[] buffer = new byte[1024];
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
}
}
zis.closeEntry();
zipEntry = zis.getNextEntry();
}
} catch (Exception e) {
e.printStackTrace();
if (zipFile != null)
zipFile.close();
}
if (zipFile != null)
zipFile.close();
} else {

}
fileZip = null;
}
### Java ZIP 文件名乱码解决方案 在 Java 中使用 `java.util.zip` 包生成 ZIP 压缩包时,如果文件名包含非 ASCII 字符(如中文),可能会出现乱码问题。这是由于 ZIP 格式的默认编为 IBM437 或 UTF-8(取决于具体实现)。以下是几种常见的解决方法: #### 方法一:强制指定文件名为 UTF-8 编 通过设置 JVM 参数 `-Dfile.encoding=UTF-8` 来确保整个程序运行环境采用 UTF-8 编[^1]。此方式适用于开发环境中已经统一编的情况。 另一种更灵活的方式是在写入 ZipEntry 之前手动转换文件名的编: ```java import java.io.*; import java.nio.charset.StandardCharsets; import java.util.zip.*; public class Utf8Zip { public static void main(String[] args) throws IOException { String fileName = "测试.txt"; // 含有中文的文件名 try (FileOutputStream fos = new FileOutputStream("example.zip"); CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32()); ZipOutputStream zos = new ZipOutputStream(cos)) { byte[] content = "这是一个测试".getBytes(StandardCharsets.UTF_8); // 手动将文件名转为 UTF-8 编并存储到 ZipEntry 中 ZipEntry entry = new ZipEntry(new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); zos.putNextEntry(entry); zos.write(content); zos.closeEntry(); } } } ``` 这种方法的核心在于利用 ISO-8859-1 对应的字节流表示法间接支持 UTF-8 的文件名[^2]。 --- #### 方法二:使用第三方库 Apache Commons Compress Apache Commons Compress 提供了更好的跨平台兼容性和扩展功能。它允许开发者显式定义压缩条目的字符集,从而避免因系统默认编不同而导致的乱码现象。 以下是一个基于该库的例子: ```java import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import java.io.FileOutputStream; import java.nio.charset.Charset; public class CommonCompressExample { public static void main(String[] args) throws Exception { Charset charset = Charset.forName("UTF-8"); // 显式声明使用的字符集 File output = new File("output.zip"); try (FileOutputStream fos = new FileOutputStream(output); ArchiveOutputStream aos = new ZipArchiveOutputStream(fos)) { ((ZipArchiveOutputStream)aos).setEncoding(charset.name()); // 设置编 String fileName = "测试文件.txt"; ZipArchiveEntry entry = new ZipArchiveEntry(fileName); aos.putArchiveEntry(entry); String data = "这里是文件的内容."; aos.write(data.getBytes(charset)); // 使用相同的字符集写入数据 aos.closeArchiveEntry(); } } } ``` 这种方式不仅解决文件名乱码问题,还增强了代可读性和维护性[^1]。 --- #### 总结 以上两种方法各有优劣。第一种适合轻量级场景下的快速修复;而第二种则更适合大型项目或者需要长期维护的应用程序。无论选择哪种方案,在实际应用前都需充分考虑目标系统的运行环境以及可能存在的其他约束条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值