首页 > 编程语言 >Java开发:文件上传和下载

Java开发:文件上传和下载

时间:2024-09-25 14:51:36浏览次数:9  
标签:Java String File fileName file dirPath 上传 response 下载

一、文件上传

使用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;这里要在本地留存一份文件,可以参考hutool的FileUtil临时文件(temp)做改进
            String dirPath = "D:\\桌面\\bx";
            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);
        }
    }

测试:
在这里插入图片描述
此时还会在D:\桌面\bx留存一份文件

一、文件下载

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

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

代码示例:

    @RequestMapping(value = "/downloadBytes")
    @ResponseBody
    public 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/png
        response.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;
        }
    }

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

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

    /**
     * 下载
     *
     * @param fileName
     * @param response
     */
    @RequestMapping(value = "/download")
    public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
    //dirPath 为从哪里下载,这里写的是String dirPath = "D:\\桌面\\bx"; 意思是从dirPath 下载文件名为fileName的文件
        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/png
        response.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);
        }
    }

postman测试结果:
在这里插入图片描述
点这里就可以保存到文件夹;
参考:https://blog.csdn.net/hefrankeleyn/article/details/140909190

标签:Java,String,File,fileName,file,dirPath,上传,response,下载
From: https://blog.csdn.net/qq_44543774/article/details/142491805

相关文章

  • Java基础部分-运算符
    算术运算符:+,-,*,/,%,++,--inta=10;intb=20;intc=25;intd=25;System.out.println(a+b);System.out.println(a-b);System.out.println(a*b);System.out.println(a/(double)b);//强制转......
  • 程序员必备Java面试题大总结!
    1、Mysql索引1.1索引的类型可以是String类型吗?聚簇索引----数据和索引放一块,像主键索引,具有唯一性(Innodb就是)数据库第一范式:必须要有id,这个id是自带索引的。一般用自增id,字符串可以做id,但是不好,像uuid做的id是随机的,都没有排序!!!不像自增id维护索引的成本会很低1.2什么是......
  • 双token三验证Java实现(解决单token可能存在的问题)
    1.单token存在的问题在正常的业务中,我们经常用到JWT生成单token进行后续的请求验证,但该模式有没有存在什么问题吗?其实是有问题的,主要是token有效期设置长短的问题,如果设置的比较短,用户会频繁的登录,如果设置的比较长,会不太安全,因为token一旦被黑客截取的话,就可以通过此tok......
  • 用easyVget下载B站油管视频
    B站油管等视频平台简直就是无所不有的宝库,动漫、番剧、纪录片、科普,更有海量的学习资源,可以极大地满足你的视觉欲和求知欲。 作为一只视频仓鼠,我热衷于下载自己感兴趣的视频到本地,不用担心视频被和谐、不用担心卡顿、不用担心网络流量,还能方便地处理视频(比如提取音频、二次剪辑......
  • 学习JAVA前的基础部分
    常用关键字:1.所有的标识符都应该以字母(A—Zanda-z),美元符($),下划线(_)开始,首字符之后可以是字母,美元符,下划线或者任何数字。2.Java所需要的组成部分都需要名字。类名、变量名以及方法都需要被称为标识符。3.标识符是大小写敏感的数据类型​ 强类型语言:要求变量的使用要严格符合......
  • Java基础部分-变量
    Java是一种强类型语言,每个变量都必须声明其类型Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。typevarName[=value][{,varName[=value]}];//数据类型变量名=值;可以使用逗号隔开来声明多个同类型变量。//类变量staticstaticdoublesal......
  • Understanding the difference between a Java keystore and a truststore
    Atruststoreisafilethatcontainsoneormorepubliccertificates,butnoprivatekeys. Akeystoreisafilethatcontainsoneormorepubliccertificatesandoneormoreprivatekeys.Thisistypicallya"chain"wherethekeystorecontain......
  • java中多态的扩展性
    创建一个动物父类和狗,猫子类,当这些子类中有共同方法只是实现不同时,我们可以利用多态的扩展性classAnimal{publicvoideat(){System.out.println("吃饭");}publicvoidsheep(){System.out.println("睡觉");}}classDogextendsAnima......
  • DC00015基于java web校园网上购物系统
    1、项目功能演示DC00015【含配套文档】基于javaweb校园网上购物系统2、项目功能描述 基于javaweb校园网上购物系统分为用户和系统管理员两个角色。2.1用户功能1、系统登录、用户注册、忘记密码2、商品浏览、商品详情3、购物车、付款4、我的订单5、修改密码、......
  • JavaScript 之父联手近万名开发者集体讨伐 Oracle:给 JavaScript 一条活路吧!
    JavaScript之父联手近万名开发者集体讨伐Oracle:给JavaScript一条活路吧!投递人 itwriter 发布于 2024-09-2401:08 评论(6) 有1528人阅读 原文链接 [收藏] « »近日,据外媒消息,JavaScript杰出人士和至少9000名其他相关方签署了一封联名信,再次要求Oracle......