Java读取文件报错java.lang.IllegalArgumentException-MALFORMED

举报
KevinQ 发表于 2024/10/18 09:12:35 2024/10/18
【摘要】 在工作中,最近遇到一个需要批量处理文件的需求,一种方法是将多个文件的压缩包上传后,又后台程序解压来逐个处理文件。按照这种思路,就需要我们来解压文件,并分别对压缩包中的文件进行处理。然而,使用Java解析zip压缩包时遇到的一个问题,问题代码如下:public static ZipFile readZipFromInputStream(InputStream inputStream) { ...

在工作中,最近遇到一个需要批量处理文件的需求,一种方法是将多个文件的压缩包上传后,又后台程序解压来逐个处理文件。按照这种思路,就需要我们来解压文件,并分别对压缩包中的文件进行处理。

然而,使用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;
        }
    }

通过这样的优化,我们不仅解决了不同操作系统下压缩包编码不一致可能导致的问题,还提高了代码的简洁性和可维护性。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。