当前位置: 首页 > article >正文

JAVA实现压缩包解压兼容Windows系统和MacOs

目标:JAVA实现压缩包解压获取图片素材

问题:Windows系统和MacOs压缩出来的zip内容有区别

MacOs会多出来

以及本身一个文件夹

而windows则不会。为了解决这个问题。兼容mac的压缩包增加一层过滤

要知道

ZipInputStream 可以读取 ZIP 文件中的条目,包括文件和文件夹。当使用 ZipInputStream 遍历 ZIP 文件时,它会按照 ZIP 文件中的顺序返回每个条目,包括嵌套在文件夹内的文件

所以,只要过滤掉文件夹以及"__MACOSX/"开头的文件,就可以取到所有正常的图片了。

import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import qunar.tc.oss.OSSClient;
import qunar.tc.oss.PutObjectResponse;


/**
 * zip服务
 */
@Service
@Slf4j
public class ZipServiceImpl implements ZipService {

    @Resource
    private OSSClient ossClient;

    @Resource
    private ImageService imageService;


    @Override
    public ZipFileUploadData uploadImgZip(MultipartFile file) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        QMonitor.recordOne("ZipServiceImpl.uploadImgZip.total");
        if (file.isEmpty() || file.getContentType() == null) {
            throw new BusinessException("文件不能为空");
        }
        // 判断文件类型是否为zip
        if (!file.getContentType().equals("application/zip")) {
            throw new BusinessException("上传文件类型错误,请上传zip文件");
        }
        ZipFileUploadData zipFileUploadData = new ZipFileUploadData();
        List<String> imageUrls = new ArrayList<>();

        // 解压zip
        try (ZipInputStream zis = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"))) {
            ZipEntry zipEntry;
            int index = 1;
            while ((zipEntry = zis.getNextEntry()) != null) {
                //判断是否为文件夹(此处为了兼容macos系统压缩包,过滤MACOSX文件夹素材以及文件夹)
                if (zipEntry.getName().startsWith("__MACOSX/") || zipEntry.isDirectory()) {
                    zis.closeEntry();
                    continue;
                }
                // 处理图片文件
                if (isImageFile(zipEntry.getName())) {
                    String imageUrl = processImageFile(zis, index);
                    if (imageUrl.isEmpty()) {
                        log.error("压缩包内图片上传失败");
                        throw new BusinessException("压缩包内图片上传失败");
                    }
                    imageUrls.add(imageUrl);
                } else {
                    // 处理非图片文件,抛出异常
                    log.error("压缩包内上传文件类型错误,请上传图片文件");
                    throw new BusinessException("压缩包内上传文件类型错误,请上传图片文件");
                }
                zis.closeEntry();  // 确保在处理完每个条目后关闭
                index++;
            }

            // 判断是否解析得到了图片列表
            if (CollectionUtils.isEmpty(imageUrls)) {
                log.error("压缩包内图片图片上传失败");
                throw new BusinessException("压缩包内图片图片上传失败");
            }
            zipFileUploadData.setNumIconInfo(imageUrls);
            PutObjectResponse putObjectResponse = getZipUploadUrl(file);
            if (putObjectResponse == null || putObjectResponse.getUrl().isEmpty()) {
                log.error("压缩包上传失败");
                throw new BusinessException("压缩包上传失败");
            }
            zipFileUploadData.setZipUrl(putObjectResponse.getUrl());
        } catch (IOException e) {
            log.error("读取ZIP文件时发生错误", e);
            throw new BusinessException("读取ZIP文件时发生错误");
        } catch (Exception e) {
            log.error("上传zip压缩包处理发生错误", e);
            throw new BusinessException(e.getMessage());
        } finally {
            QMonitor.recordQuantile("ZipServiceImpl.uploadImgZip.final", stopwatch.elapsed(TimeUnit.MILLISECONDS));
        }
        // 返回结果
        QMonitor.recordOne("ZipServiceImpl.uploadImgZip.success");
        return zipFileUploadData;
    }

    /**
     * 获取zip上传url
     * @param file 文件
     * @return PutObjectResponse 上传结果
     * @throws IOException IO异常
     */
    private PutObjectResponse getZipUploadUrl(MultipartFile file) throws IOException {
        String extName = "";
        String originalFilename = file.getOriginalFilename();
        if (originalFilename != null && !originalFilename.isEmpty()) {
            extName = StringUtils.getFilenameExtension(originalFilename);
        }
        String fileName = String.format("zip-%s.%s", UUID.randomUUID().toString().replace("-", ""), extName);
        File tempFile = Files.createTempFile(null, fileName).toFile();
        file.transferTo(tempFile);
        PutObjectResponse response = ossClient.putObject(fileName, tempFile);
        // 确保上传后删除临时文件
        Files.delete(tempFile.toPath());
        return response;
    }


    private boolean isImageFile(String fileName) {
        // 这里可以添加更多的图片格式检查
        return fileName.toLowerCase().endsWith(".png") || fileName.toLowerCase().endsWith(".jpg") || fileName.toLowerCase().endsWith(".jpeg");
    }

    private String processImageFile(InputStream inputStream, int index) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            baos.write(buffer, 0, length);
        }
        byte[] imageBytes = baos.toByteArray();
        String base64Image = Base64.getEncoder().encodeToString(imageBytes);
        String fileName = String.valueOf(index).concat(".png");
        return imageService.uploadImg(base64Image, fileName);
    }


}


http://www.kler.cn/a/306233.html

相关文章:

  • Vim 编辑器学习笔记
  • Vue计算属性computed
  • catchadmin-webman 宝塔 部署
  • Prometheus面试内容整理-Exporters
  • 网络基础概念与应用:深入理解计算机网络
  • 算法——长度最小的子数组(leetcode209)
  • 【机器学习】期望最大化算法的基本概念以及再高斯混合模型的应用
  • Go语言错误处理详解
  • Cubieboard2(一) 官方镜像使用与配置
  • 【LLM多模态】文生视频评测基准VBench
  • llama3论文阅读
  • 火箭动力原理精解【1】
  • 学习大数据DAY57 新的接口配置
  • AI学习指南深度学习篇-RMSprop的数学原理
  • Python 课程11-Web 开发
  • Android 10.0 mtk平板camera2横屏预览旋转90度横屏保存圆形预览缩略图旋转90度功能实现
  • 蓝桥杯3. 压缩字符串
  • 掌握远程管理的艺术:揭秘Python的pywinrm库
  • 【OJ刷题】双指针问题3
  • 通义灵码在Visual Studio上
  • spring-TransactionTemplate 编程式事务
  • C#笔记10 Thread类怎么终止(Abort)和阻止(Join)线程
  • SQLite的入门级项目学习记录(四)
  • [项目][WebServer][Task]详细讲解
  • python绘制3d建筑
  • flask-sqlalchemy的模型类两个表,既有一对一又有一对多的情况时,解决方法