【已解决】Java zip解压时候 malformed input off : 4, length : 1

  • 作者: 凯哥Java(公众号:凯哥Java)
  • 工作小总结
  • 时间:2023-09-28 13:46
  • 2273人已阅读
简介 Java zip解压时候 malformed 解决方案

🔔🔔🔔好消息!好消息!🔔🔔🔔

有需要的朋友👉:联系凯哥 微信号 kaigejava2022

需求:通过页面上传ZIP文件后,对zip文件进行解压。

遇到的错误:在进行zip解压的时候错误如下:

ecd7f9884f267e7a13c0c34a32c796e0.png

先看报错前的:

/**
 * 解压缩ZIP文件
 * @param zipFile ZIP文件
 * @param destDir 目标路径
 */
public static void zipDecompress(File zipFile, File destDir) {
    byte[] buffer = new byte[1024];
    try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
        ZipEntry entry = zis.getNextEntry();
        if(!destDir.exists()){
            destDir.mkdirs();
        }
        while (entry != null) {


            File file = new File(destDir, entry.getName());
            if (entry.isDirectory()) {
                file.mkdirs();
            } else {
                File parent = file.getParentFile();
                if (!parent.exists()) {
                    parent.mkdirs();
                }
                try (FileOutputStream fos = new FileOutputStream(file)) {
                    int len;
                    while ((len = zis.read(buffer)) > 0) {
                        fos.write(buffer, 0, len);
                    }
                }
            }
            entry = zis.getNextEntry();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

分析原因:

1c3f561f1157e995bf3d9c7f287c16ea.png

然后查询后得到:

813a16c89406f68255d19f9fd2da40e4.png

如果在Java中解压文件时报错 “malformed”,通常表示压缩文件的格式不正确或损坏。下面是一些可能导致此错误的常见原因和解决方法:
我试了集中方法都不行,最后看有人说是编码问题,加上GBK编码格式后解析成功

File file = new File(filePath);
            InputStream inputStream = new FileInputStream(file,Charset.forName("GBK"));

解决方案:

所以修改代码,在生产ZipInputStream时候添加编码:

5be824fb5e08b1b0f5ce02ea5fc823f7.png



扩展:


这个功能涉及到的知识点:

  1. web的文件上传

  2. 将上传文件上传到服务器上

  3. 对zip文件进行解压

一、web文件上传:

@RequestMapping("/create-picture")
public ResponseResult<String> createPicture(@RequestParam(value = "file") MultipartFile zipFile){
    createPictureReportingThread.startCreateDataReport(param,zipFile);
    return ResponseResult.success("请等待五分钟后,在报告列表中查询");
}



二、将上传的文件上传到服务器上

public void makePictureReport( MultipartFile MultipartZipFile) {
    InputStream fis = null;
    try {
        String originalFileName = MultipartZipFile.getOriginalFilename();
        String extendFileName = originalFileName.substring( originalFileName.lastIndexOf('.'));
        System.out.println("extendFileName:"+extendFileName);
        //校验是否为ZIP
        //生成新的文件名称
        String saveFileName = UUID.randomUUID().toString().replace("-","");
        String relativeFileDir = DateUtil.format(new Date(), "yyyyMMddHHmmSSS")+ File.separator+ saveFileName ;
        //上传文件
        String fileBasePath = baseFileDir+relativeFileDir;
        FileUtils.uploadFile(MultipartZipFile,fileBasePath , saveFileName+extendFileName);

        //解压zip文件
        String decompressPath = fileBasePath+ File.separator+ "decompress"+ File.separator;
        File zipFile = new File(fileBasePath+File.separator+ saveFileName+extendFileName);
        File decompressFile = new File(decompressPath);
        ZipUtils.zipDecompress(zipFile ,decompressFile);


    } catch (Exception e) {
        throw new RuntimeException(e);
    }

}

其中的FileUtils:

@Slf4j
public class FileUtils {
 /**
     * 上传文件
     * @param file              文件
     * @param filepath          保存路径
     * @param filename          文件名称
     */
    public static String uploadFile(MultipartFile file, String filepath, String filename) throws Exception {
        if (ObjectUtils.isEmpty(file)) {
            log.info("文件为空");
            return null;
        }
        File descFile = new File(filepath,filename);
        log.info("上传文件到"+descFile.getAbsolutePath());
        //父目录不存在则建立相关文件夹
        if(!descFile.getParentFile().exists()){
            descFile.getParentFile().mkdirs();
        }
        if (!descFile.exists()) {
            descFile.createNewFile();
        }
        // 文件保存

        try(InputStream source = file.getInputStream()) {
            org.apache.commons.io.FileUtils.copyInputStreamToFile(source,descFile);
        } catch (Exception e) {
            log.info("文件保存出现异常");
            e.printStackTrace();
            throw new BusinessException(-200,"文件保存出现异常");
        }
        log.info("文件上传成功");
        return descFile.getCanonicalPath();
    }
}


三、ZIP文件解压

ZipUtils代码类:

import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.Arrays;
import java.util.Objects;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
 * @BelongsProject: kaigejava
 * @BelongsPackage: com.kaigejava.util
 * @Author: kaigejava
 * @CreateTime: 2023-09-28  10:33
 * @Description: zip的工具类
 * @Version: 1.0
 */
public class ZipUtils {
    /**
     * 压缩文件(支持单个文件和单个文件夹)
     * @param sourceFile 被压缩文件/文件夹
     * @param zipFile Zip文件
     */
    public static void zipCompress(File sourceFile, File zipFile) {
        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
            // 设置压缩方法
            zos.setMethod(ZipOutputStream.DEFLATED);
            zos.setLevel(Deflater.BEST_COMPRESSION); // 默认为-1,压缩级别,1速度快,效率低,9 速度满,效率高
            // zos.setLevel(Deflater.BEST_SPEED);
            zos.setComment("zip文件说明");
            // 处理文件夹
            if (sourceFile.exists() && sourceFile.isDirectory() && Objects.nonNull(sourceFile.listFiles())){
                Arrays.stream(Objects.requireNonNull(sourceFile.listFiles())).forEach(file -> {
                    addZipFile(file, zos);
                });
            }else{
                addZipFile(sourceFile, zos);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 向ZIP中添加文件
     * @param file 源文件
     * @param zos zip输出流
     */
    private static void addZipFile(File file, ZipOutputStream zos){
        if (!file.exists() || file.isDirectory()){
            throw new RuntimeException("文件不存在或该文件为文件夹,请检查");
        }
        try {
            // 读入文件
            FileInputStream fis = new FileInputStream(file);
            // 创建压缩对象并设置一些属性
            ZipEntry entry = new ZipEntry(file.getName());
            entry.setMethod(ZipEntry.DEFLATED); // 压缩方法默认为DEFLATED
            // entry.setMethod(ZipEntry.STORED); // STORED(不压缩)。当使用STORED压缩方法时,需要设置未压缩的数据大小和CRC-32校验和,否则压缩和解压缩时会出现错误。
            entry.setSize(file.length()); // 设置未压缩的数据大小,这里设置的是文件大小
            // 计算 CRC-32 校验码
            // byte[] data = Files.readAllBytes(file.toPath());
            // CRC32 crc = new CRC32();
            // crc.update(data);
            // entry.setCrc(crc.getValue()); // 设置CRC-32校验和,用于保证压缩后的数据完整性,尽量别手动设置,可以通过CRC-32计算
            entry.setCompressedSize(file.length()); // 设置压缩后的数据大小,这里设置的是使用DEFLATED方法压缩后的数据大小
            entry.setExtra(new byte[]{}); // 设置额外的数据,这里设置为空
            entry.setComment("file comment"); // 设置ZipEntry的注释,即文件说明
            entry.setCreationTime(FileTime.from(Instant.now())); // 设置文件的创建时间
            entry.setLastAccessTime(FileTime.from(Instant.now())); // 设置文件的最后访问时间
            entry.setLastModifiedTime(FileTime.from(Instant.now())); // 设置文件的最后修改时间。
            // 向ZIP输出流中添加一个ZIP实体,构造方法中的name参数指定文件在ZIP包中的文件名
            zos.putNextEntry(entry);
            // 向ZIP实体中写入内容
            byte[] buf = new byte[1024];
            int len;
            while ((len = fis.read(buf)) > 0) {
                zos.write(buf, 0, len);
            }
            // 关闭ZipEntry
            zos.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 解压缩ZIP文件
     * @param zipFile ZIP文件
     * @param destDir 目标路径
     */
    public static void zipDecompress(File zipFile, File destDir) {
        byte[] buffer = new byte[1024];
        try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile),Charset.forName("GBK"))) {
            ZipEntry entry = zis.getNextEntry();
            if(!destDir.exists()){
                destDir.mkdirs();
            }
            while (entry != null) {


                File file = new File(destDir, entry.getName());
                if (entry.isDirectory()) {
                    file.mkdirs();
                } else {
                    File parent = file.getParentFile();
                    if (!parent.exists()) {
                        parent.mkdirs();
                    }
                    try (FileOutputStream fos = new FileOutputStream(file)) {
                        int len;
                        while ((len = zis.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                    }
                }
                entry = zis.getNextEntry();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  }


TopTop