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);
}
}