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();
}
}
你是不是没有在压缩前创建一个空文件夹条目?
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.自定义目录
可以尝试将缓冲输出流转换成字节数组的操作放在压缩流关闭之后执行,即在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();
}
}