iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >SpringBoot下载文件的实现及速度对比
  • 294
分享到

SpringBoot下载文件的实现及速度对比

2024-04-02 19:04:59 294人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言文件来源文件下载1、OutputStream形式2、ResponseEntity形式两种方式下载速度比较后话前言 承上篇上传文件之后,本文就主要介绍下SpringBoot下下

前言

承上篇上传文件之后,本文就主要介绍下SpringBoot下下载文件的方式,大致有两种Outputstream与ResponseEntity,并大概看一下速度对比

文件来源

这里还是以GridFS为例,主要演示的还是从monGo下载下来的文件,如果是本地服务器上的文件,前端传以文件路径直接获取流即可,如下:


InputStream in = new FileInputStream(System.getProperty("user.dir") + filePath);

接下来就演示下使用GridFsTemplate下载文件,mongo的配置其实上篇已经贴过了,这里就直接贴代码了,具体的就不做解释了


@Service
@Slf4j
public class MongoConfig extends AbstractMongoConfiguration {
 
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private GridFSBucket gridFSBucket;
 
    @Override
    public MongoClient mongoClient() {
        MongoClient mongoClient = getMongoClient();
        return mongoClient;
    }
 
    public MongoClient getMongoClient() {
        // mongoDB地址列表
        List<ServerAddress> serverAddresses = new ArrayList<>();
        serverAddresses.add(new ServerAddress("10.1.61.101:27017"));
        // 连接认证
        MongoCredential credential = MongoCredential.createCredential("root", "admin", "Root_123".toCharArray());
        MongoClientOptions.Builder builder = MongoClientOptions.builder();
 
        //最大连接数
        builder.connectionsPerHost(10);
        //最小连接数
        builder.minConnectionsPerHost(0);
        //超时时间
        builder.connectTimeout(1000*3);
        // 一个线程成功获取到一个可用数据库之前的最大等待时间
        builder.maxWaitTime(5000);
        //此参数跟connectionsPerHost的乘机为一个线程变为可用的最大阻塞数,超过此乘机数之后的所有线程将及时获取一个异常.eg.connectionsPerHost=10 and threadsAllowedToBlockForConnectionMultiplier=5,最多50个线程等级一个链接,推荐配置为5
        builder.threadsAllowedToBlockForConnectionMultiplier(5);
        //最大空闲时间
        builder.maxConnectionIdleTime(1000*10);
        //设置池连接的最大生命时间。
        builder.maxConnectionLifeTime(1000*10);
        //连接超时时间
        builder.SocketTimeout(1000*10);
 
        MongoClientOptions myOptions = builder.build();
        MongoClient mongoClient = new MongoClient(serverAddresses, credential, myOptions);
        return mongoClient;
    }
 
    @Override
    protected String getDatabaseName() {
        return "notifyTest";
    }
 
    
    public String getFilesDataBaseName() {
        return "notifyFiles";
    }
 
    
    public MongoDbFactory getDbFactory(String dataBaseName) {
        MongoDbFactory dbFactory = null;
        try {
            dbFactory = new SimpleMongoDbFactory(getMongoClient(), dataBaseName);
        } catch (Exception e) {
            log.error("Get mongo client have an error, please check reason...", e.getMessage());
        }
        return dbFactory;
    }
 
    
    public GridFsTemplate getGridFS() {
        return new GridFsTemplate(getDbFactory(getFilesDataBaseName()), mongoTemplate.getConverter());
    }
 
    @Bean
    public GridFSBucket getGridFSBuckets() {
        MongoDatabase db = getDbFactory(getFilesDataBaseName()).getDb();
        return GridFSBuckets.create(db);
    }
 
    
    public GridFsResource convertGridFSFile2Resource(GridFSFile gridFsFile) {
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFsFile.getObjectId());
        return new GridFsResource(gridFsFile, gridFSDownloadStream);
    }
}

对比上篇配置,新增加的两个方法主要为了应对springBoot2.x之后,GridFsTemplate的findOne()方法返回从GridFSDBFile改为GridFSFile,导致文件下载时不能使用以前的GridFSDBFile 操作流了,所以加了转换操作

文件下载

分别把两种方式的下载实现贴出来

1、OutputStream形式


    @RequestMapping(value = "/download2", method = RequestMethod.GET)
    public void downLoad2(httpservletResponse response, String id) {
        userService.download2(response, id);
    }

controller层如上,只是测试所以很简略,因为是流的形式所以并不需要指定输出格式,下面看下service层实现


    
    @Override
    public void download2(HttpServletResponse response, String id) {
        GridFsTemplate gridFsTemplate = new GridFsTemplate(mongoConfig.getDbFactory(mongoConfig.getFilesDataBaseName()), mongoTemplate.getConverter());
        // 由于springBoot升级到2.x 之后 findOne方法返回由 GridFSDBFile 变为 GridFSFile 了,导致下载变得稍微有点繁琐
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
        String fileName = gridFSFile.getFilename();
        GridFsResource gridFsResource = mongoConfig.convertGridFSFile2Resource(gridFSFile);
        // 从此处开始计时
        long startTime = System.currentTimeMillis();
        InputStream in = null;
        OutputStream out = null;
        try {
            // 这里需对中文进行转码处理
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
            // 告诉浏览器弹出下载对话框
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            byte[] buffer = new byte[1024];
            int len;
            // 获得输出流
            out = response.getOutputStream();
            in = gridFsResource.getInputStream();
            while ((len = in.read(buffer)) > 0) {
               out.write(buffer, 0 ,len);
            }
        } catch (IOException e) {
            log.error("transfer in error .");
        } finally {
            try {
                if (null != in)
                    in.close();
                if (null != out)
                    out.close();
                log.info("download file with stream total time : {}", System.currentTimeMillis() - startTime);
            } catch (IOException e){
                log.error("close IO error .");
            }
        }
    }

可以看到篇幅较长,注释也已经都在代码里了

2、ResponseEntity形式


    @RequestMapping(value = "/download", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public Object downLoad(String id) {
        return userService.download(id);
    }

controller需要指定输出格式application/octet-stream,标明是以流的形式下载文件,下面看下service层


    
    @Override
    public ResponseEntity<byte[]> download(String id) {
        GridFsTemplate gridFsTemplate = new GridFsTemplate(mongoConfig.getDbFactory(mongoConfig.getFilesDataBaseName()), mongoTemplate.getConverter());
        // 由于springBoot升级到2.x 之后 findOne方法返回由 GridFSDBFile 变为 GridFSFile 了,导致下载变得稍微有点繁琐
        GridFSFile gridFSFile = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(id)));
        String fileName = gridFSFile.getFilename();
        GridFsResource gridFsResource = mongoConfig.convertGridFSFile2Resource(gridFSFile);
        // 从此处开始计时
        long startTime = System.currentTimeMillis();
        try {
            InputStream in = gridFsResource.getInputStream();
            // 请求体
            byte[] body = IOUtils.toByteArray(in);
            // 请求头
            HttpHeaders httpHeaders = new HttpHeaders();
            // 这里需对中文进行转码处理
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
            // 告诉浏览器弹出下载对话框
            httpHeaders.add("Content-Disposition", "attachment;filename=" + fileName);
            ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(body, httpHeaders, HttpStatus.OK);
            log.info("download file total with ResponseEntity time : {}", System.currentTimeMillis() - startTime);
            return responseEntity;
        } catch (IOException e) {
            log.error("transfer in error .");
        }
        return null;
    }

上面用到了IOUtils工具类,依赖如下


<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

两种方式下载速度比较

经过测试,当文件小于1m内两种方式速度差不多,然后我测了5m的文件,结果如下:

可以看到OutputStream略慢一点点,当文件再大时这边也并没有作测试,总之本人推荐使用ResponseEntity形式下载文件~

后话

如果只是想显示某个路径下的图片而并不需要下载,那么采用如下形式:


    @RequestMapping(value = "/application/file/show", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
    public Object downloadFile(@RequestParam("path") String filePath) {
        try {
            InputStream in = new FileInputStream(System.getProperty("user.dir") + filePath);
            byte[] bytes = new byte[in.available()];
            in.read(bytes);
            return bytes;
        } catch (IOException e) {
            log.error("transfer byte error");
            return buildMessage(ResultModel.FAIL, "show pic error");
        }
    }

需要注意上述的available()方法,该方法是返回输入流中所包含的字节数,方便在读写操作时就能得知数量,能否使用取决于实现了InputStream这个抽象类的具体子类中有没有实现available这个方法。

如果实现了那么就可以取得大小,如果没有实现那么就获取不到。

例如FileInputStream就实现了available方法,那么就可以用new byte[in.available()];这种方式。

但是,网络编程的时候Socket中取到的InputStream,就没有实现这个方法,那么就不可以使用这种方式创建数组

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: SpringBoot下载文件的实现及速度对比

本文链接: https://www.lsjlt.com/news/158892.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringBoot下载文件的实现及速度对比
    目录前言文件来源文件下载1、OutputStream形式2、ResponseEntity形式两种方式下载速度比较后话前言 承上篇上传文件之后,本文就主要介绍下SpringBoot下下...
    99+
    2024-04-02
  • javascriptBlob对象实现文件下载
    目录说明一、Blob对象二、前端三、后端总结说明 最近遇到一个需求,文件下载,但需要鉴权,这就意味着不能用后台返回下载链接的方式进行下载,因为一旦被别人拿到这条链接,就可以不需要任何...
    99+
    2024-04-02
  • springboot如何实现文件下载呢?
    转自: springboot如何实现文件下载呢? 下文笔者讲述SpringBoot实现文件下载的方法分享,如下所示: 文件存储在服务器指定位置 import java.io.*;import java.net.URLEncoder;impo...
    99+
    2023-09-07
    spring boot
  • vue+element+springboot实现文件下载进度条展现功能示例
    目录1. 需求背景2. 优化方案3. 具体实现3.1 前端代码3.2 后台代码4. 总结本文主要介绍了vue+element+springboot实现文件下载进度条展现功能示例,分享...
    99+
    2024-04-02
  • SpringBoot如何实现文件下载功能
    这篇文章主要介绍“SpringBoot如何实现文件下载功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringBoot如何实现文件下载功能”文章能帮助大家解决问题。1. 将文件以流的形式一次性...
    99+
    2023-07-05
  • SpringBoot实现文件上传下载实时进度条功能(附源码)
    目录0. 引言1. 思路2. 实操2.1 实现文件上传实时进度条功能2.2 实现文件下载实时进度条功能3. 项目源码4. 总结0. 引言 记得刚入行的时候,做了一个文件上传的功能,因...
    99+
    2022-11-13
    SpringBoot文件上传下载实时进度条 SpringBoot 实时进度条 SpringBoot 进度条
  • Vue文件下载进度条的实现过程
    目录需求场景:实现原理:优化过程:下载方法的组件引入mixinVuex配置进度条最终效果图参考文章:需求场景: 1、大文件压缩过后依旧很大,接口返回response速度过慢,页面没有...
    99+
    2024-04-02
  • SpringBoot如何实现上传和下载文件
    这篇文章主要介绍SpringBoot如何实现上传和下载文件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!技术概述我们的项目是实现一个论坛。在论坛上发布博客时应该要可以上传文件,用户阅读博客是应该要可以下载文件。于是我...
    99+
    2023-06-20
  • au3实现文件对比
    ;要打开的文件Local $file = FileOpen("D:\au3_test\ice2.conf", 0)Local $file2 = FileOpen("D:\au3_test\ice.conf", 0); 检查打开的文件是否可读...
    99+
    2023-01-31
    文件
  • 【SpringBoot+MyBatisPlus】文件上传与文件下载的应用与实现
    文章目录 前言一.文件上传二.改进三.文件下载四.上传图片/回显图片 前言 一次“上传文件”的点击蕴含着一轮请求,我们要做的就是针对每一次的请求进行i/o处理,并返回给前端用户 一.文...
    99+
    2023-09-08
    spring boot java mybatis
  • React和Vue实现文件下载进度条
    目录一、需求场景二、实现原理三、react 实现步骤1. 托管静态资源2. 封装hook3. 使用hook四、vue 实现步骤1. 托管静态资源2. 封装hook3. 使用hook五...
    99+
    2023-05-18
    React下载进度条 Vue下载进度条
  • SpringBoot实现文件下载功能的方式分享
    1. 将文件以流的形式一次性读取到内存,通过响应输出流输出到前端 @RequestMapping("/download") public void download(String ...
    99+
    2023-03-23
    SpringBoot实现文件下载 SpringBoot文件下载 SpringBoot下载
  • Java 实现浏览器下载文件及文件预览
    插曲想记录一下,以后可以来粘贴复制用。 一、浏览器下载文件 setContentType() 该实体头的作用是让服务器告诉浏览器它发送的数据属于什么文件类型。 没有缓存 resp...
    99+
    2024-04-02
  • SpringBoot实现文件上传下载功能小结
    最近做的一个项目涉及到文件上传与下载。前端上传采用百度webUploader插件。有关该插件的使用方法还在研究中,日后整理再记录。本文主要介绍SpringBoot后台对文件上传与下载的处理。单文件上传// 单文件上传@RequestMapp...
    99+
    2023-05-31
    spring boot 文件上传
  • HTML怎么实现文件下载对话框
    本篇内容介绍了“HTML怎么实现文件下载对话框”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!文件下载对话框我们先在当前目录下创建 foo.t...
    99+
    2023-06-08
  • JavaScript实现文本相似度对比
    目录一、发现问题二、解决问题1、编辑距离的概念2、测试文本3、代码实现4、相似度对比结果一、发现问题 在开发过程中,难免会使用到2个(多个)文本内容处理,一是便于宏观知道文本的重合度...
    99+
    2024-04-02
  • python下载文件带进度条怎么实现
    要实现带进度条的文件下载,可以使用`urllib.request`模块和`tqdm`库。以下是一个示例代码:```pythonimp...
    99+
    2023-09-26
    python
  • Android实现文件下载
    前言 总体思路:下载文件到应用缓存路径,在相册创建文件夹,Copy过去,通知相册刷新。 下载文件到APP缓存路径,这样可避免Android高版本读取本地权限问题, 准备 impl...
    99+
    2024-04-02
  • ASP.NETMVC实现文件下载
    思路 点击一个链接,把该文件的Id传递给控制器方法,遍历文件夹所有文件,根据ID找到对应文件,并返回FileResult类型。 与文件相关的Model: namespace MvcA...
    99+
    2022-11-13
    ASP.NET MVC 文件下载
  • thinkphp5实现文件下载
    public function download() { $famlePath = $_GET[‘resum’]; f i ...
    99+
    2023-09-01
    php
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作