Java读取文件报错java.lang.IllegalArgumentException-MALFORMED
在工作中,最近遇到一个需要批量处理文件的需求,一种方法是将多个文件的压缩包上传后,又后台程序解压来逐个处理文件。按照这种思路,就需要我们来解压文件,并分别对压缩包中的文件进行处理。
然而,使用Java解析zip压缩包时遇到的一个问题,问题代码如下:
public static ZipFile readZipFromInputStream(InputStream inputStream) {
try {
// 创建临时文件
java.io.File tempFile = java.io.File.createTempFile("tempzipfile", ".zip");
tempFile.deleteOnExit();
// 将 InputStream 内容写入临时文件
try (OutputStream outputStream = new FileOutputStream(tempFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
return new ZipFile(tempFile);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
这个函数的作用是,将.zip
格式的压缩包读取为java.util.zip.ZipFile
对象。
例如,我们简单的执行将zip压缩包中的每个文件名打印出来:
public static void getZipFile(ZipFile zipFile) {
zipFile.stream().forEach(zipEntry -> {
System.out.println(zipEntry.getName());
});
}
public static void main(String[] args) throws IOException {
String zipFilePath = "D:\\temp\\test.zip";
ZipFile zipFile = readZipFromInputStream(new FileInputStream(zipFilePath));
getZipFile(zipFile);
}
但是在实际执行时,有时会报错,如下:
Exception in thread "main" java.lang.IllegalArgumentException: MALFORMED
at java.util.zip.ZipCoder.toString(ZipCoder.java:58)
at java.util.zip.ZipFile.getZipEntry(ZipFile.java:583)
at java.util.zip.ZipFile.access$900(ZipFile.java:60)
at java.util.zip.ZipFile$ZipEntryIterator.next(ZipFile.java:539)
at java.util.zip.ZipFile$ZipEntryIterator.next(ZipFile.java:495)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
......
经过检索,发现这个错误与zip文件中是否存在中文名有关,windows环境下压缩包默认编码为GBK,而Linux/Mac环境下,压缩包默认编码为UTF-8。因此,为了解决此问题,需要在获取ZipFile时指定编码格式。
将函数中的return语句修改为:
return new ZipFile(tempFile, Charset.forName("GBK"));
执行时便不爆错了。
但是仍然存在一个问题,即如果一个压缩包是使用Linux/Mac系统创建的,但是在系统所运行的Windows环境下进行解压,是不是还是会报错呢?
为了应对这种情况,我们再次对代码进行优化。我们首先尝试以 GBK 格式获取 ZipFile
,如果出现异常,再尝试以 UTF - 8 格式获取。优化后的代码如下:
try {
// 创建临时文件
java.io.File tempFile = java.io.File.createTempFile("tempzipfile", ".zip");
tempFile.deleteOnExit();
// 将 InputStream 内容写入临时文件
try (OutputStream outputStream = new FileOutputStream(tempFile)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
try {
return new ZipFile(tempFile, Charset.forName("GBK"));
} catch (Exception e) {
return new ZipFile(tempFile, StandardCharsets.UTF_8);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
此外,我们还可以使用一些现有的工具类来对整个方法进行进一步的优化。例如,我们可以使用 Apache Commons IO 中的 IOUtils.copy
方法来更简洁地将输入流的内容复制到文件输出流中。优化后的代码如下:
public static ZipFile readZipFromInputStream(InputStream inputStream) {
try {
// 创建临时文件
java.io.File tempFile = java.io.File.createTempFile("tempzipfile", ".zip");
tempFile.deleteOnExit();
IOUtils.copy(inputStream, new FileOutputStream(tempFile));
try {
return new ZipFile(tempFile, Charset.forName("GBK"));
} catch (Exception e) {
return new ZipFile(tempFile, StandardCharsets.UTF_8);
}
} catch (IOException e) {
return null;
}
}
通过这样的优化,我们不仅解决了不同操作系统下压缩包编码不一致可能导致的问题,还提高了代码的简洁性和可维护性。
- 点赞
- 收藏
- 关注作者
评论(0)