当前位置: 首页 > news >正文

Java开发:文件上传和下载

Java开发:文件的上传和下载

文章目录

  • Java开发:文件的上传和下载
    • 一、文件上传
    • 二、文件下载
      • (1)使用BufferedInputStream的好处
      • (2)`@RequestMapping(value = "/download")`
      • (3)下载文件响应头设置,以及解决中文文件名正常下载
      • (4)后端两种写下载的方式:返回void和返回byte[]

一、文件上传

  • 使用MultipartFile 类型接收参数;

  • 调用上传有两种方式:

    方式一:使用curl命令

    curl -F "file=@/data/filename.txt" http://localhost:8080/upload --verbose
    

    方式二:使用html,写一个form表单:

    同样是POST请求,为何文件上传的功能会慢?其中一个原因是, 使用multipart/form-data编码,需要对数据进行分块处理,增加时间开销。服务器端也需要解析这些分块数据,并将其转化为文件或其它形式处理,这个过程也会增加时间开销。

    <!DOCTYPE html>
    <html lang="en">
    <head><meta charset="UTF-8"><title>Upload</title>
    </head>
    <body>
    <div style="margin-left: 300px; margin-top: 50px;"><form action="/upload" method="post" enctype="multipart/form-data" accept-charset="UTF-8"><input type="file" name="file"/><br/><br/><button type="submit">上传</button></form>
    </div>
    </body>
    </html>
    
  • Java后端上传示例:

    @RequestMapping(value = "/upload", method = RequestMethod.POST)public String upload(@RequestParam("file") MultipartFile file) {try {String dirPath = uploadPath + File.separator + port;File dirFile = new File(dirPath);if (!dirFile.exists()) {boolean ok = dirFile.mkdirs();log.debug("===> {} create dir {}", ok, dirPath);}String fileName = file.getOriginalFilename();String filePath = dirPath + File.separator + fileName;File dest = new File(filePath);file.transferTo(dest);log.debug("===> success upload file: {}", filePath);return dest.getName();} catch (Exception e) {throw new RuntimeException(e);}}

二、文件下载

(1)使用BufferedInputStream的好处

  1. 提高读取效率:在内存中维护一个缓冲区(buffer),默认8kb,一次性读取一个较大的块。后续从缓冲区中读取数据;

    read() 方法,读取一个字节
    
  2. 支持标记和重置:mark和reset方法

(2)@RequestMapping(value = "/download")

不写method参数,让其支持所有的HTTP方法,无论是GET、POST、PUT还是其它。

(3)下载文件响应头设置,以及解决中文文件名正常下载

  1. 指定字符集;
  2. 指定文件类型;
  3. 指定文件名。注意,对文件名进行编码,解决中文文件名正常下载;
        // 需要添加一些头信息,响应才知道是下载的文件// 添加字符集response.setCharacterEncoding("UTF-8");// 文件类型: 方式一:指定具体的文件类型;方式二:指定其是一个二进制格式// 其它的文件类型:text/plain、application/pdf、application/vnd.ms-excel、image/jpeg、image/pngresponse.setContentType("application/octet-stream");// 文件的名称,解决中文乱码String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);// attachment (附件) 提示浏览器下载, inline 提示浏览器显示内容(如果支持的话)response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");// 文件的长度response.setContentLength((int) file.length());

(4)后端两种写下载的方式:返回void和返回byte[]

返回byte[]:需要在内存中存储整个文件内容,对于大文件可能会导致内存问题。

代码示例:

    @RequestMapping(value = "/downloadBytes")@ResponseBodypublic byte[] downloadBytes(@RequestParam("fileName") String fileName, HttpServletResponse response) {String dirPath = uploadPath + File.separator + port;String filePath = dirPath + File.separator + fileName;File file = new File(filePath);if (!file.exists() && file.isFile()) {response.setStatus(HttpServletResponse.SC_NOT_FOUND);return null;}checkState(file.exists() && file.isFile(), "file not exists: %s", filePath);// 需要添加一些头信息,响应才知道是下载的文件// 添加字符集response.setCharacterEncoding("UTF-8");// 文件类型: 方式一:指定具体的文件类型;方式二:指定其是一个二进制格式// 其它的文件类型:text/plain、application/pdf、application/vnd.ms-excel、image/jpeg、image/pngresponse.setContentType("application/octet-stream");// 文件的名称,解决中文乱码String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);// attachment (附件) 提示浏览器下载, inline 提示浏览器显示内容(如果支持的话)response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");try (InputStream inputStream = new FileInputStream(file)) {byte[] bytes = new byte[(int) file.length()];int readLen = inputStream.read(bytes);log.debug("====> readLen {}", readLen);return bytes;} catch (Exception e) {log.error(e.getMessage());response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);return null;}}

返回 void 的方式通常会使用流式传输(streaming)的方式来发送文件内容,这意味着文件是以一段一段的方式发送的。这样做有几个好处:

  1. 节省内存:整个文件不需要一次性加载到内存中,减少了内存占用。对于大文件尤其重要。
  2. 更高效:可以立即开始传输文件的部分内容,而不需要等待整个文件加载完成。

代码示例:

    /*** 下载** @param fileName* @param response*/@RequestMapping(value = "/download")public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {String dirPath = uploadPath + File.separator + port;String filePath = dirPath + File.separator + fileName;File file = new File(filePath);if (!(file.exists() && file.isFile())) {response.setStatus(HttpServletResponse.SC_NOT_FOUND);log.debug("====> file not exists: {}", filePath);return;}// 需要添加一些头信息,响应才知道是下载的文件// 添加字符集response.setCharacterEncoding("UTF-8");// 文件类型: 方式一:指定具体的文件类型;方式二:指定其是一个二进制格式// 其它的文件类型:text/plain、application/pdf、application/vnd.ms-excel、image/jpeg、image/pngresponse.setContentType("application/octet-stream");// 文件的名称,解决中文乱码String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);// attachment (附件) 提示浏览器下载, inline 提示浏览器显示内容(如果支持的话)response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");// 文件的长度response.setContentLength((int) file.length());try (InputStream inputStream = new FileInputStream(file);BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {byte[] bytes = new byte[1024 * 16];int len = 0;ServletOutputStream outputStream = response.getOutputStream();while ((len = bufferedInputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);}outputStream.flush();} catch (Exception e) {log.error(e.getMessage());response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);}}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 按摩虎口穴位的作用
  • Laravel php框架与Yii php 框架的优缺点
  • 上线前端系统
  • 7.C基础_数组
  • DAP-Seq:解锁转录因子结合位点的新钥匙
  • 眼在手外-机器人坐标系与相机坐标系标定方法
  • CTF-web基础 web服务器
  • 实战项目导航
  • 基于Django框架的挂号诊疗系统(源码+论文+部署讲解等)
  • 基于JAVA的物资管理系统设计与实现
  • C语言基础题:迷宫寻路(C语言版)
  • 软设之网络诊断命令
  • JavaScript青少年简明教程:事件及处理
  • DevOps 相关知识点总结
  • 1037:计算2的幂
  • 《剑指offer》分解让复杂问题更简单
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • CSS居中完全指南——构建CSS居中决策树
  • JavaScript标准库系列——Math对象和Date对象(二)
  • javascript面向对象之创建对象
  • JS数组方法汇总
  • Redis在Web项目中的应用与实践
  • Redis中的lru算法实现
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • Service Worker
  • vue-cli在webpack的配置文件探究
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • 翻译--Thinking in React
  • 和 || 运算
  • 欢迎参加第二届中国游戏开发者大会
  • 记一次删除Git记录中的大文件的过程
  • 如何在 Tornado 中实现 Middleware
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 线性表及其算法(java实现)
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #define,static,const,三种常量的区别
  • $.ajax()参数及用法
  • (02)vite环境变量配置
  • (4) PIVOT 和 UPIVOT 的使用
  • (7)STL算法之交换赋值
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (十)Flink Table API 和 SQL 基本概念
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)视频码率,帧率和分辨率的联系与区别
  • *** 2003
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET 反射 Reflect
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)