ZipOutputStream 如何压缩空文件夹

ZipOutputStream 如何压缩空文件夹

目前的问题是 使用 ZipOutputStream 压缩的空文件夹,变成了文件。


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipDemo {
    public static void main(String[] args) throws IOException {
        String folderPath = "path/to/folder";
        String zipFilePath = "path/to/zipfile.zip";

        File folder = new File(folderPath);
        ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath));

        // 添加空文件夹到 ZIP 文件中
        ZipEntry zipEntry = new ZipEntry(folder.getName() + "/");
        zipOut.putNextEntry(zipEntry);
        zipOut.closeEntry();

        zipOut.close();
    }
}

你是不是没有在压缩前创建一个空文件夹条目?

  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/1095269
  • 这篇博客也不错, 你可以看下ZipOutputStream使用
  • 除此之外, 这篇博客: 文件下载--ZipOutputStream批量&OutputStream单个文件下载图片到本地中的 1.使用ZipOutputStream批量打包文件到本地 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • demo:

    @RestController
    @RequestMapping("download")
    @Slf4j
    public class DownLoadController {
    
        @RequestMapping("test")
        public void test(HttpServletResponse response) {
            try {
                String nowTimeString = "ll";
                //文件的名称
                String downloadFilename = nowTimeString + ".zip";
                //转换中文否则可能会产生乱码
                downloadFilename = URLEncoder.encode(downloadFilename, "UTF-8");
                // 指明response的返回对象是文件流
                response.setContentType("application/octet-stream");
                // 设置在下载框默认显示的文件名
                response.setHeader("Content-Disposition", "attachment;filename=" + downloadFilename);
                ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
                ArrayList<String> files = Lists.newArrayList(
                        "http://***/commodity_qrcode/qrcode_test/1983207019.jpg", "http://****/commodity_qrcode/qrcode_test/1979780937.jpg", "http://***/commodity_qrcode/qrcode_test/1979780935.jpg",
                        "http://***/commodity_qrcode/qrcode_test/1979780934.jpg", "http://****/commodity_qrcode/qrcode_test/1152809.jpg", "http://****/commodity_qrcode/qrcode_test/1152808.jpg",
                       "http://***/commodity_qrcode/qrcode_test/1152807.jpg",
                        "https://****/lll/test/2020-12/memo/f86dc6ba7a7642ac83f9f4409af2227e.jpg");
    
                for (int i = 0; i < files.size(); i++) {
                    URL url = new URL(files.get(i));
                    //目录不能重复,否则会duplicate entry: ll/
                    //因此需要加个时间戳或者是uuid作为后缀
                    //也可以根据文件地址作为目录,会自动根据路径分区文件夹,一个/一个文件目录
                    zos.putNextEntry(new ZipEntry("ll/" + i+ ".jpg"));
                    //此时会自动分级目录,
    //                zos.putNextEntry(new ZipEntry(files.get(i));
    
                    InputStream fis = url.openConnection().getInputStream();
                    byte[] buffer = new byte[1024];
                    int r = 0;
                    while ((r = fis.read(buffer)) != -1) {
                        zos.write(buffer, 0, r);
                    }
                    fis.close();
                }
    
                //强制把数据输出,清空缓存区,(必须要,因为一部分数据还在缓冲区)
                //面向缓冲区的,不强制输出就关闭,数据可能不完整
                //最后再关闭读写流调用close()就完成了
                zos.flush();
                //关闭输出流
                zos.close();
            } catch (Exception e) {
                log.error("下载失败", e);
    
            }
        }
      }
    

    结果: 1.根据url分目录
    在这里插入图片描述
    2.自定义目录
    在这里插入图片描述

  • 以下回答由chatgpt基于相关博客总结生成:

    可以尝试将缓冲输出流转换成字节数组的操作放在压缩流关闭之后执行,即在finally块中执行bos.toByteArray(),这样可以确保压缩文件的所有内容都已经输出到缓冲输出流中,而不会出现缺失的情况。同时,为了保证资源的释放和异常情况的处理,需要将缓冲输出流和压缩输出流的关闭操作都放在finally块中。具体代码如下:

    public static void compressFolder(File folder, File zipFile) throws IOException {
        try (
                FileOutputStream fos = new FileOutputStream(zipFile);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
                ZipOutputStream zos = new ZipOutputStream(bos)
        ) {
            compressFolder(folder, folder.getName(), zos);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }
    
    private static void compressFolder(File folder, String parentFolderName, ZipOutputStream zos) throws IOException {
        if (!folder.exists()) {
            return;
        }
        if (folder.isDirectory()) {
            if (folder.list().length == 0) {
                // 空文件夹
                zos.putNextEntry(new ZipEntry(parentFolderName + File.separator + folder.getName() + File.separator));
                zos.closeEntry();
            } else {
                for (File file : folder.listFiles()) {
                    compressFolder(file, parentFolderName + File.separator + folder.getName(), zos);
                }
            }
        } else {
            try (
                    FileInputStream fis = new FileInputStream(folder);
                    BufferedInputStream bis = new BufferedInputStream(fis)
            ) {
                zos.putNextEntry(new ZipEntry(parentFolderName + File.separator + folder.getName()));
                byte[] buffer = new byte[1024];
                int len;
                while ((len = bis.read(buffer)) >= 0) {
                    zos.write(buffer, 0, len);
                }
                zos.closeEntry();
            } catch (IOException e) {
                e.printStackTrace();
                throw e;
            }
        }
    }
    
    public static void main(String[] args) {
        File folder = new File("xxx");
        File zipFile = new File("xxx.zip");
        try {
            compressFolder(folder, zipFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }