1. 将文件以流的形式一次性读取到内存,通过响应输出流输出到前端
/** * @param path 想要下载的文件的路径 * @param response * @功能描述 下载文件: */@requestmapping("/download")public void download(string path, httpservletresponse response) { try { // path是指想要下载的文件的路径 file file = new file(path); log.info(file.getpath()); // 获取文件名 string filename = file.getname(); // 获取文件后缀名 string ext = filename.substring(filename.lastindexof(".") + 1).tolowercase(); log.info("文件后缀名:" + ext); // 将文件写入输入流 fileinputstream fileinputstream = new fileinputstream(file); inputstream fis = new bufferedinputstream(fileinputstream); byte[] buffer = new byte[fis.available()]; fis.read(buffer); fis.close(); // 清空response response.reset(); // 设置response的header response.setcharacterencoding("utf-8"); //content-disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存 //attachment表示以附件方式下载 inline表示在线打开 "content-disposition: inline; filename=文件名.mp3" // filename表示文件的默认名称,因为网络传输只支持url编码的相关支付,因此需要将文件名url编码后进行传输,前端收到后需要反编码才能获取到真正的名称 response.addheader("content-disposition", "attachment;filename=" + urlencoder.encode(filename, "utf-8")); // 告知浏览器文件的大小 response.addheader("content-length", "" + file.length()); outputstream outputstream = new bufferedoutputstream(response.getoutputstream()); response.setcontenttype("application/octet-stream"); outputstream.write(buffer); outputstream.flush(); } catch (ioexception ex) { ex.printstacktrace(); }}
2. 将输入流中的数据循环写入到响应输出流中,而不是一次性读取到内存,通过响应输出流输出到前端
/*** @param path 指想要下载的文件的路径* @param response* @功能描述 下载文件:将输入流中的数据循环写入到响应输出流中,而不是一次性读取到内存*/@requestmapping("/downloadlocal")public void downloadlocal(string path, httpservletresponse response) throws ioexception { // 读到流中 inputstream inputstream = new fileinputstream(path);// 文件的存放路径 response.reset(); response.setcontenttype("application/octet-stream"); string filename = new file(path).getname(); response.addheader("content-disposition", "attachment; filename=" + urlencoder.encode(filename, "utf-8")); servletoutputstream outputstream = response.getoutputstream(); byte[] b = new byte[1024]; int len; //从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1 while ((len = inputstream.read(b)) > 0) { outputstream.write(b, 0, len); } inputstream.close();}
3. 下载网络文件到本地
/*** @param path 下载后的文件路径和名称* @param netaddress 文件所在网络地址* @功能描述 网络文件下载到服务器本地*/@requestmapping("/netdownloadlocal")public void downloadnet(string netaddress, string path) throws ioexception { url url = new url(netaddress); urlconnection conn = url.openconnection(); inputstream inputstream = conn.getinputstream(); fileoutputstream fileoutputstream = new fileoutputstream(path); int bytesum = 0; int byteread; byte[] buffer = new byte[1024]; while ((byteread = inputstream.read(buffer)) != -1) { bytesum += byteread; system.out.println(bytesum); fileoutputstream.write(buffer, 0, byteread); } fileoutputstream.close();}
4. 网络文件获取到服务器后,经服务器处理后响应给前端
/** * @param netaddress * @param filename * @param isonline * @param response * @功能描述 网络文件获取到服务器后,经服务器处理后响应给前端 */@requestmapping("/netdownloadnet")public void netdownloadnet(string netaddress, string filename, boolean isonline, httpservletresponse response) throws exception { url url = new url(netaddress); urlconnection conn = url.openconnection(); inputstream inputstream = conn.getinputstream(); response.reset(); response.setcontenttype(conn.getcontenttype()); if (isonline) { // 在线打开方式 文件名应该编码成utf-8 response.setheader("content-disposition", "inline; filename=" + urlencoder.encode(filename, "utf-8")); } else { //纯下载方式 文件名应该编码成utf-8 response.setheader("content-disposition", "attachment; filename=" + urlencoder.encode(filename, "utf-8")); } byte[] buffer = new byte[1024]; int len; outputstream outputstream = response.getoutputstream(); while ((len = inputstream.read(buffer)) > 0) { outputstream.write(buffer, 0, len); } inputstream.close();}
5. 常见异常和问题
(1)响应对象无需通过return返回
原因: 响应对象是可以不用作为方法返回值返回的,其在方法执行时已经开始输出,且其无法与@restcontroller配合,以json格式返回给前端
解决办法: 删除return语句
(2)返回前端的文件名必须进行url编码
原因: 网络传输只能传输特定的几十个字符,需要将汉字、特殊字符等经过base64等编码来转化为特定字符,从而进行传输,而不会乱码
urlencoder.encode(filename, "utf-8")
(3)io流有待学习
下面是重写后的句子:函数read()用于从输入流中读取数据的下一个字节,并返回该字节的整型值,值的范围在0到255之间。如果因为已经到达流末尾而没有可用的字节,则返回-1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
2:read(byte[] b) : 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。该方法会一直阻塞直到输入数据可用、检测到文件末尾或者抛出异常。如果 b 的长度为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1
以上就是springboot如何实现文件下载功能的详细内容。