文件下载主要分单个下载和批量下载
其实都是常规的IO操作,整体思路大概是用输入流将文件写入到指定位置,再用输出流将文件读到浏览器
1.先来介绍单个文件下载
/**
* 单个下载
* @param response
* @param attachUrl 文件地址
* @param attachName 文件名称
* @throws IOException
*/
public void downloadRecord(HttpServletResponse response, String attachUrl,
String attachName) throws IOException {
OutputStream out=null;
try {
response.setContentType("audio/mp3 ");
//注意:这里new String()的意义是为了解决中文不展示问题
response.addHeader("Content-Disposition", "attachment;filename=" +
new String(attachName.getBytes("utf-8"), "ISO-8859-1"));
out = response.getOutputStream();
FileInputStream in= new FileInputStream (attachUrl);
byte[] bytes = new byte[1024];
int len = 0;
while(-1 != (len=in.read(bytes))){
out.write(bytes,0, len);//输出给浏览器
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(null != out){
out.close();
}
}
}
说几个细节:
1.文件名是中文的话需要用new String(attachName.getBytes("utf-8"), "ISO-8859-1")来转换以下,不然不显示
2.read(byte[])和read(byte[],int off,int len)的区别
2.再来说一说批量下载
批量下载会用到压缩包(Zip),我这边有2种思路:
①文件源地址,将需要下载的文件放到虚拟的File文件中,为什么说虚拟,因为new File(文件源url),实际上不会创建文件夹,new的File就相当于一个篮子,存放要下载的文件,然后压缩这个file,返回给浏览器。
②提供一个临时文件夹,替代如上说的“篮子”,将待下载的文件输出到临时文件夹中,压缩、返回给浏览器,最后删除掉这个临时文件夹。
//工具类 filePath:待压缩路径 zipOut:压缩流
public static void fileToZip(String fileName,String filePath,ZipOutputStream zipOut) throws IOException {
// 需要压缩的文件
File file = new File(filePath);
// 获取文件名称,如果有特殊命名需求,可以将参数列表拓展,传fileName
//String fileName = file.getName();
FileInputStream fileInput = new FileInputStream(filePath);
// 缓冲
byte[] bufferArea = new byte[1024 * 10];
BufferedInputStream bufferStream = new BufferedInputStream(fileInput, 1024 * 10);
// 将当前文件作为一个zip实体写入压缩流,fileName代表压缩文件中的文件名称
zipOut.putNextEntry(new ZipEntry(fileName));
int length = 0;
// 最常规IO操作,不必紧张
while ((length = bufferStream.read(bufferArea, 0, 1024 * 10)) != -1) {
zipOut.write(bufferArea, 0, length);
}
//关闭流
fileInput.close();
// 需要注意的是缓冲流必须要关闭流,否则输出无效
bufferStream.close();
// 压缩流不必关闭,使用完后再关
}
我的应用场景是:前端传过来多条数据,后台对数据做处理
public void downloadMore(HttpServletResponse response, String rowData) throws IOException {
String rowDataNew = StringEscapeUtils.unescapeHtml(rowData);
List<PhoneAttachDownLoadModel>
phoneAttachDownLoadModels=JSONArray.parseArray(rowDataNew,
PhoneAttachDownLoadModel.class);
String filePath = "";
String fileName = "";
String zipName = "录音下载";
//1.rowData,获取到录音地址、录音名称、指定下载到哪
ServletOutputStream outputStream = null;
FileInputStream inputStream = null;
zipFilePath = FileUtils.getTempPath()+File.separator+zipName ;
ZipOutputStream zipOutputStream=new ZipOutputStream(new FileOutputStream(zipFilePath));
try {
for (PhoneAttachDownLoadModel row : phoneAttachDownLoadModels) {
filePath =row.getAttachName();//录音地址
fileName = row.getCustomerName() +".mp3";//录音名称
//3.调用fileToZip方法将暂存文件夹下的文件压缩成zip
FileUtils.fileToZip(fileName,filePath,zipOutputStream);
}
//4.将zip输出给浏览器
response.setHeader("Content-Disposition", "attchment;filename=" +
new String(zipName.getBytes("utf-8"), "ISO-8859-1")+".zip");
outputStream = response.getOutputStream(); //向页面发送流数据
inputStream = new FileInputStream(tempFloder+File.separator+zipName+".zip");
IOUtils.copy(inputStream, outputStream);
} catch (IOException e) {
log.info("批量下载失败");
e.printStackTrace();
}finally {
// 关闭输入流
if (inputStream != null){
inputStream.close();
}
if (outputStream != null){
outputStream.close();
}
if (zipOutputStream!= null){
zipOutputStream.close();
}
}
//5.删除暂存文件夹中的文件
File file=new File(tempFloder);
FileUtils.deleteFile(file);
}
细节说明:
1.用StringEscapeUtils.unescapeHtml(rowData)来处理"
2.先使用的流后关闭
3.ServletOutputStream流不需要关闭,并且可以通过response.getOutputStream()获取
一个录音下载,我写了有10次,都没有搞得很明白,如果大家有不明白的地方,我们一起讨论~