基于Java实现minio8下载文件并压缩zip

本文介绍了一种在服务器端实现多文件下载的方法,通过递归构建文件结构并压缩成ZIP格式,支持文件夹层级结构的保持不变。具体步骤包括构建文件路径、组织ZIP文件结构及内容、下载文件至服务器并生成ZIP文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:多文件下载需要压缩zip并返回前端,文件夹层级结构保持不变
思路:先通过递归构建出所有的目录结构并生成zip,再服务器下载文件写入zip
实现:
1. 构建出每个文件的fullName,如果为顶层文件fullName即为当前文件名,如果有父级文件fullName为父级文件+ “/” + 子文件
示例: /opt/compose/docker-compose.yaml
	private void loadFullName(StorageVO storage) {
        if (storage.getParentId() == null) {
            storage.setFullName(storage.getName());
        } else {
            Optional<Storage> optional = this.repository.findById(storage.getParentId());
            if (optional.isPresent()) {
                StorageVO parent = StorageVO.of(optional.get());
                loadFullName(parent);
                storage.setFullName(parent.getFullName() + File.separator + storage.getName());
            } else {
                storage.setFullName(storage.getName());
            }
        }
    }
2. 前端传入需要下载的文件或文件夹id,查出所有的文件和文件夹,调用fullName方法,构建出zip需要的数据结构
public List<StorageVO> buildZip(List<String> ids) {

        BooleanBuilder predicate = new BooleanBuilder();
        predicate.and(QStorage.storage.deleted.eq(false));
        predicate.and(QStorage.storage.id.in(ids));
        List<StorageVO> storages = ListUtil.toList(this.repository.findAll(predicate))
                .stream()
                .map(storage -> StorageVO.of(storage).withChildren(storage.getChildren()))
                .toList();

        storages.addAll(storages.stream().map(StorageVO::getChildren).filter(Objects::nonNull).flatMap(Collection::stream).toList());
        storages.forEach(this::loadFullName);
        return storages;
    }
3.把步骤2构建好的数据结构写入到zip流,并根据是否为文件夹创建目录结构,在服务器下载文件写入到zip
public void downloadFileToServer(String tmpDir, List<StorageVO> treeParams, ZipArchiveOutputStream zipArchiveOutputStream) throws IOException {
        if (CollUtil.isNotEmpty(treeParams)) {
            for (StorageVO child : treeParams) {
                if (child.getIsDirectory()) {
                    tmpDir = tmpDir + File.separator + child.getFullName();
                    File mkdir = FileUtil.mkdir(tmpDir);
                    ZipArchiveEntry entry = new ZipArchiveEntry(mkdir, child.getFullName());
                    zipArchiveOutputStream.putArchiveEntry(entry);
                } else {
                    tmpDir = tmpDir + File.separator + child.getFullName();
                    File file = new File(tmpDir);
                    ZipArchiveEntry entry = new ZipArchiveEntry(file, child.getFullName());
                    zipArchiveOutputStream.putArchiveEntry(entry);

                    try (InputStream inputStream = minioHandle.download(child.getPath())) {
                        int i;
                        byte[] bytes = new byte[1024];
                        while ((i = inputStream.read(bytes)) != -1) {
                            zipArchiveOutputStream.write(bytes, 0, i);
                        }
                    }
                    zipArchiveOutputStream.closeArchiveEntry();
                    zipArchiveOutputStream.flush();
                }
            }
        }
    }
4. 下载文件,并把文件流写入response
public void downloadFiles(List<StorageVO> storages, HttpServletResponse response) {

        String tmpDir = System.getProperty("java.io.tmpdir") + "downloads";
        if (!new File(tmpDir).exists()) {
            FileUtil.mkdir(tmpDir);
        }
        ZipArchiveOutputStream zipArchiveOutputStream = null;
        try {
            String name = storages.size() > 1 ? storages.get(0).getName() + "等" + storages.stream()
                    .filter(storageVO -> !storageVO.getIsDirectory()).toList().size() + "个文件" : storages.get(0).getName();
            response.reset();
            response.setHeader("Accept-Ranges", "bytes");
            String fileName = URLEncoder.encode(name + ".zip", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setContentType("application/json;charset=utf-8");

            zipArchiveOutputStream = new ZipArchiveOutputStream(response.getOutputStream());
            zipArchiveOutputStream.setUseZip64(Zip64Mode.AsNeeded);

            //在服务器上生成指定文件
            downloadFileToServer(tmpDir, storages, zipArchiveOutputStream);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(zipArchiveOutputStream);
            FileUtil.del(tmpDir);
        }
    }
5. controller代码.
    @RequestMapping("/{ids}/downloads")
    public Result<Object> downloads(@PathVariable("ids") String ids, HttpServletResponse response) {
        try {
            storageService.downloadFiles(storageService.buildZip(Arrays.stream(ids.split(",")).toList()), response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException("downloadFileError", "下载失败,请重试");
        }
        return Result.success();
    }

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值