实现java压缩文件或文件夹以流返回vue前端下载
前一阵子需要实现这个需求,在网上找了挺久都找不到完整的前后端代码,要不就是只有前端没有后端,要么就是压缩出来文件末梢损坏,当时看了一下流也没有问题,就想着自己写一个博客。
思路是这样的:
- 在服务端生成相应的文件或者文件夹
- 压缩文件或文件夹
- 以流的形式返回前端下载
那我们直接上代码:
第一步就直接跳过,来到第二步,先上工具类
这是我自己整理的工具类
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipUtil {
private ZipUtil(){
}
public static void doCompress(String srcFile, String zipFile) throws IOException {
doCompress(new File(srcFile), new File(zipFile));
}
/**
* 文件压缩
* @param srcFile 目录或者单个文件
* @param zipFile 压缩后的ZIP文件
*/
public static void doCompress(File srcFile, File zipFile) throws IOException {
ZipOutputStream out = null;
try {
out = new ZipOutputStream(new FileOutputStream(zipFile));
doCompress(srcFile, out);
} catch (Exception e) {
throw e;
} finally {
out.close();//记得关闭资源
}
}
public static void doCompress(String filelName, ZipOutputStream out) throws IOException{
doCompress(new File(filelName), out);
}
public static void doCompress(File file, ZipOutputStream out) throws IOException{
doCompress(file, out, "");
}
public static void doCompress(File inFile, ZipOutputStream out, String dir) throws IOException {
if ( inFile.isDirectory() ) {
File[] files = inFile.listFiles();
if (files!=null && files.length>0) {
for (File file : files) {
String name = inFile.getName();
if (!"".equals(dir)) {
name = dir + "/" + name;
}
ZipUtil.doCompress(file, out, name);
}
}
} else {
ZipUtil.doZip(inFile, out, dir);
}
}
public static void doZip(File inFile, ZipOutputStream out, String dir) throws IOException {
String entryName = null;
if (!"".equals(dir)) {
entryName = dir + "/" + inFile.getName();
} else {
entryName = inFile.getName();
}
ZipEntry entry = new ZipEntry(entryName);
out.putNextEntry(entry);
int len = 0 ;
byte[] buffer = new byte[1024];
FileInputStream fis = new FileInputStream(inFile);
while ((len = fis.read(buffer)) > 0) {
out.write(buffer, 0, len);
out.flush();
}
out.closeEntry();
fis.close();
}
/**
* 获取目录下的所有文件
*
* @param obj
* @return
*/
public static ArrayList<File> getListFiles(Object obj) {
File directory = null;
if (obj instanceof File) {
directory = (File) obj;
} else {
directory = new File(obj.toString());
}
ArrayList<File> files = new ArrayList<File>();
if (directory.isFile()) {
files.add(directory);
return files;
} else if (directory.isDirectory()) {
File[] fileArr = directory.listFiles();
for (int i = 0; i < fileArr.length; i++) {
File fileOne = fileArr[i];
files.addAll(getListFiles(fileOne));
}
}
return files;
}
public static void downloadFiles(String filePath,HttpServletResponse response){
try {
// 读到流中
InputStream inStream = new FileInputStream(filePath);
// 设置输出的格式
response.setContentType("application/zip");
response.setCharacterEncoding("utf-8");
response.addHeader("Content-Disposition", "attachment;");
// 循环取出流中的数据
byte[] b = new byte[100];
int len;
while ((len = inStream.read(b)) > 0) {
response.getOutputStream().write(b, 0, len);
}
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] getFileByteArray(File file) {
long fileSize = file.length();
if (fileSize > Integer.MAX_VALUE) {
System.out.println("file too big...");
return null;
}
byte[] buffer = null;
try (FileInputStream fi = new FileInputStream(file)) {
buffer = new byte[(int) fileSize];
int offset = 0;
int numRead = 0;
while (offset < buffer.length
&& (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
offset += numRead;
}
// 确保所有数据均被读取
if (offset != buffer.length) {
throw new IOException("Could not completely read file "
+ file.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
return buffer;
}
/**
* 删除空目录
* @param dir 将要删除的目录路径
*/
private static void doDeleteEmptyDir(String dir) {
boolean success = (new File(dir)).delete();
if (success) {
System.out.println("Successfully deleted empty directory: " + dir);
} else {
System.out.println("Failed to delete empty directory: " + dir);
}
}
/**
* 递归删除目录下的所有文件及子目录下所有文件
* @param dir 将要删除的文件目录
* @return boolean Returns "true" if all deletions were successful.
* If a deletion fails, the method stops attempting to
* delete and returns "false".
*/
public static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
//递归删除目录中的子目录下
for (int i=0; i<children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// 目录此时为空,可以删除
return dir.delete();
}
}
接下来我们就可以测试一下压缩
public static void main(String[] args) throws IOException {
ZipUtil.doCompress("D:\\test\\", "D:\\test\\test.zip");
}
这里是代表把D盘test目录压缩成test.zip这个文件,这一步的时候可以看看自己压缩出来的压缩包会不会报错,不会就可以进行最后一步下载了。
下载
最后调用工具类的下载方法即可,已经封装好了
public static void downloadFiles(String filePath,HttpServletResponse response){
try {
// 读到流中
InputStream inStream = new FileInputStream(filePath);
// 设置输出的格式
response.setContentType("application/zip");
response.setCharacterEncoding("utf-8");
response.addHeader("Content-Disposition", "attachment;");
// 循环取出流中的数据
byte[] b = new byte[100];
int len;
while ((len = inStream.read(b)) > 0) {
response.getOutputStream().write(b, 0, len);
}
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
然后在前端请求响应的这样做
请求xxx.then(function(res){
let blob = new Blob([data], {type: 'application/zip'})
let url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = 'test'
link.click()
URL.revokeObjectURL(url)
})
到这里,就实现了java压缩文件或者目录以流的形式返回前端下载。
可以的话给个关注或者点个赞,有问题可以留言噢。
关于公众号,不定期干货。
谢谢观看!