文件下载,是从服务器下载到本地电脑。 文件下载的原理,首先通过IO流将服务器的文件读取到内存里(只有将数据读到内存,电脑才可以操作数据),读取后文件数据存放在内存中,将内存中的数据通过网络发送给本地客户端的浏览器。本地客户端的浏览器接受数据,并在本地生成对应的文件。
@RequestMapping("/download") public void downLoad(String path, HttpServletResponse response) throws UnsupportedEncodingException {
响应头信息代表的含义:
常见ContentType,
指定响应头的展示方式,主要体现在:
* 指定下载文件的文件名和保存方式。如"attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")中的filename=xxx指定了后的文件的文件名和格式
* 控制浏览器的行为。如"attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")的attachment,指定浏览器以附件的形式展示文件,即指定浏览器下载文件而不是打开文件,如果设置为inline,则是在浏览器打开文件。如果没有filename 浏览器会出现保存为的对话框。
Content-Disposition: inline Content-Disposition: attachment Content-Disposition: attachment; filename="XXX"
* 设置响应头代码
response.reset(); response.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setCharacterEncoding("utf-8");//设置编码格式为utf-8 response.setContentLength((int)file.length());//响应数据长度 response.setContentType("application/octet-stream");
通过IO流读取文件并将数据返回给浏览器
try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));OutputStream outputStream = response.getOutputStream();)是try-with-resource的语法格式,作用为try块退出时,会自动调用在()中的bis,outputStream资源的close()方法,自动关闭IO资源。(不用手动关闭了代码书写复杂度降低)
获取response的输出流OutputStream,从文件的InputStream输入流读取数据到内存,然后通过输出流写入。
try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));OutputStream outputStream = response.getOutputStream();) { byte[] bytes = new byte[1024]; int i=0; while((i=bis.read(bytes))!=-1) { outputStream.write(bytes,0,i); } }catch (Exception e) { e.printStackTrace(); }
@RequestMapping("/download") public void downLoad(String path, HttpServletResponse response) throws UnsupportedEncodingException { File file=new File(path); String fileName= file.getName(); response.reset(); response.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); response.setCharacterEncoding("utf-8"); response.setContentLength((int)file.length()); response.setContentType("application/octet-stream"); System.out.println("filename:"+fileName); try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));OutputStream outputStream = response.getOutputStream();) { byte[] bytes = new byte[1024]; int i=0; while((i=bis.read(bytes))!=-1) { outputStream.write(bytes,0,i); } }catch (Exception e) { e.printStackTrace(); } }
ZipOutputStream使用流程,
使用示例
//初始化,test.zip是写入压缩包的名称 ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream("test.zip")); //创建一个名称为test.txt新的条目,一般压缩包中有很多文件,新条目相当于创建新文件 zipOutputStream.putNextEntry(new ZipEntry("test.txt")); //写入具体内容 zipOutputStream.write("Hello World".getBytes()); //关闭条目 zipOutputStream.closeEntry(); //关闭整体压缩输出流 zipOutputStream.close();
ListpathList=new ArrayList<>(); pathList.add("xxx.txt"); pathList.add("xxx.txt"); pathList.add("xxx.txt");
response.reset(); response.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode("1.zip", "UTF-8")); response.setCharacterEncoding("utf-8");
try(ZipOutputStream zipOutputStream=new ZipOutputStream(new BufferedOutputStream(response.getOutputStream())))
for(String pathName:pathList)
File file =new File(pathName); String fileName=file.getName(); zipOutputStream.putNextEntry(new ZipEntry(fileName)); try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file))){ byte[] bytes = new byte[1024]; int i=0; while((i=bis.read(bytes))!=-1) { zipOutputStream.write(bytes,0,i); } zipOutputStream.closeEntry();
@GetMapping("/downloadlist") public void downLoadList( HttpServletResponse response ) throws UnsupportedEncodingException { ListpathList=new ArrayList<>(); pathList.add("xxx.txt"); pathList.add("xxx.txt"); pathList.add("xxx.txt"); response.reset(); response.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode("1.zip", "UTF-8")); response.setCharacterEncoding("utf-8"); response.setContentType("application/octet-stream"); try(ZipOutputStream zipOutputStream=new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()))) { for(String pathName:pathList) { File file =new File(pathName); String fileName=file.getName(); zipOutputStream.putNextEntry(new ZipEntry(fileName)); try(BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file))){ byte[] bytes = new byte[1024]; int i=0; while((i=bis.read(bytes))!=-1) { zipOutputStream.write(bytes,0,i); } zipOutputStream.closeEntry(); }catch (Exception e) { e.printStackTrace(); } } }catch (Exception e) { e.printStackTrace(); } }
关键点在ZipOutputStream中的putNextEntry() 方法上,putNextEntry()相当于往压缩包中加入子文件(也可以是子文件夹),new ZipEntry(fileName)是建立的子文件(或文件夹),如果
zipOutputStream.putNextEntry(new ZipEntry(fileName));
实际解决思路,如果要将一个文件夹下的多个文件压缩,实际效果为点开压缩包,里面有个文件夹,文件夹下是多个文件
解决,
总的来说是,操作每个文件的时候要保留前面文件夹的路径,fileName必须是ddd/a.txt,这样才会在压缩包中有文件夹
解决,
判断是文件夹还是文件,如果是文件夹,则将文件夹名称记录传给子文件,如果是文件,传过来的文件夹和文件名,在压缩包中创建对应的文件夹名和文件名,然后将数据复制给压缩包中的文件
总的来说,压缩文件或文件夹是通过fileName参数在压缩包中创建文件夹或文件,然后将数据拷贝给压缩包中的文件一份