从FTP服务器下载文件

最近写了一个接口,客户端浏览器请求,从FTP服务器下载文件,现在达成的指标是88.6M的文件,请求需要12s,不知道这个指标算不算正常。记录一下。

public void downloadFiles(String filePath, HttpServletResponse response) {
        String[] split = filePath.split("/");
        String dirPath = split[1];
        String fileName = split[2];

        FTPClient ftpClient = ftpPoolService.borrowObject();
        try {
            ftpClient.changeWorkingDirectory(dirPath);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 设置响应头,告诉浏览器这是一个字节流,浏览器处理字节流的默认方式就是下载
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName);

        try (InputStream inputStream = ftpClient.retrieveFileStream(fileName);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
             ServletOutputStream out = response.getOutputStream();
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out)){


            // 从输入流中读取数据,并写入响应输出流中。从ftp服务器传输数据到我的服务器
            byte[] buffer = new byte[2048];// 缓冲区
            int bytesRead;
            long start2 = System.currentTimeMillis();
            while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
                bufferedOutputStream.write(buffer, 0, bytesRead);
            }
            long end2 = System.currentTimeMillis();
            System.out.println("循环耗时:" + (end2 - start2));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                ftpClient.completePendingCommand();
                ftpPoolService.returnObject(ftpClient);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

下载文件耗时地方:

// 从输入流中读取数据,并写入响应输出流中
byte[] buffer = new byte[10240];// 缓冲区
int bytesRead;
long start2 = System.currentTimeMillis();
while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
    bufferedOutputStream.write(buffer, 0, bytesRead);
}
long end2 = System.currentTimeMillis();
System.out.println("循环耗时:" + (end2 - start2));

循环将文件输入流写到输出流中最耗时。

1 InputStream inputStream = ftpClient.retrieveFileStream(fileName); 从ftp服务器获取一个InputStream 对象, 该流对象用于读取ftp服务器文件的数据, 这个过程设计磁盘的IO操作, 因为ftp服务器文件是存储在磁盘上, 当通过流对象读取文件时, 就涉及到磁盘的IO操作。

2 bufferedInputStream.read(buffer) 这个就是通过一个流对象从FTP服务器中读取数据, 涉及到磁盘的IO操作.

3 bufferedOutputStream.write(buffer, 0, bytesRead); 将读取到的数据(字节)写入到输出流, 将数据写入了 ServletOutputStream,而不是直接写入磁盘。这个操作主要涉及到将数据从内存(字节数组 buffer)写入到输出流中,以便将数据发送到客户端浏览器。 客户端浏览器收到数据后,会根据响应头中的信息进行处理,例如下载文件或显示内容。 ServletOutputStream 流连接到浏览器,用于传输数据。

这个过程跟网络带宽有关,单位时间内传输的数据量。

这个过程中,数据被写入 BufferedOutputStream 的缓冲区,当缓冲区满了或者 flush() 被调用时,数据将被发送到底层的 ServletOutputStream,最终传递给客户端浏览器。这样的设计可以提高性能,因为它减少了直接写入底层流的次数,而是通过缓冲区进行批量写入。如果没有缓冲区,数据会直接写入到ServletOutputStream流中。

是否使用输出缓冲流差异

0.99 GB文件

不使用下载文件耗时:135265

try (InputStream inputStream = ftpClient.retrieveFileStream(fileName);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
             ServletOutputStream out = response.getOutputStream();
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out)
        ){


            // 从输入流中读取数据,并写入响应输出流中。从ftp服务器传输数据到我的服务器
            byte[] buffer = new byte[2048];
            int bytesRead;
            long start2 = System.currentTimeMillis();
            while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
                out .write(buffer, 0, bytesRead);
            }
            long end2 = System.currentTimeMillis();
            System.out.println("循环耗时:" + (end2 - start2));

使用下载文件耗时:134810

try (InputStream inputStream = ftpClient.retrieveFileStream(fileName);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
             ServletOutputStream out = response.getOutputStream();
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out)
        ){


            // 从输入流中读取数据,并写入响应输出流中。从ftp服务器传输数据到我的服务器
            byte[] buffer = new byte[2048];
            int bytesRead;
            long start2 = System.currentTimeMillis();
            while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
                bufferedOutputStream.write(buffer, 0, bytesRead);
            }
            long end2 = System.currentTimeMillis();
            System.out.println("循环耗时:" + (end2 - start2));

查阅资料好像是说ServletOutputStream 本身就是一种输出缓冲流,它可能在内部实现了缓冲机制。因此,添加额外的 BufferedOutputStream 可能没有太大的性能提升,因为在网络传输的过程中,底层的缓冲机制已经存在。那么现在添加输出缓冲流不是一个优化方案。

是否使用输入缓冲流差异

200.3M文件

不使用下载文件耗时:135482

try (InputStream inputStream = ftpClient.retrieveFileStream(fileName);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
             ServletOutputStream out = response.getOutputStream();
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out)
        ){


            // 从输入流中读取数据,并写入响应输出流中。从ftp服务器传输数据到我的服务器
            byte[] buffer = new byte[2048];
            int bytesRead;
            long start2 = System.currentTimeMillis();
            while ((bytesRead = inputStream .read(buffer)) != -1) {
                bufferedOutputStream.write(buffer, 0, bytesRead);
            }
            long end2 = System.currentTimeMillis();
            System.out.println("循环耗时:" + (end2 - start2));

使用下载文件耗时:134810

try (InputStream inputStream = ftpClient.retrieveFileStream(fileName);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
             ServletOutputStream out = response.getOutputStream();
             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(out)
        ){


            // 从输入流中读取数据,并写入响应输出流中。从ftp服务器传输数据到我的服务器
            byte[] buffer = new byte[2048];
            int bytesRead;
            long start2 = System.currentTimeMillis();
            while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
                bufferedOutputStream.write(buffer, 0, bytesRead);
            }
            long end2 = System.currentTimeMillis();
            System.out.println("循环耗时:" + (end2 - start2));

BufferedInputStream 的原理

通过预先读入一整段原始输入流数据至缓冲区(默认是8KB)中,而外界对BufferedInputStream的读取操作实际上是在缓冲区上进行,如果读取的数据超过了缓冲区的范围,那么BufferedInputStream负责重新从原始输入流中载入下一截数据填充缓冲区,然后外界继续通过缓冲区进行数据读取。

这样的设计的好处是:避免了大量的磁盘IO,因为原始的InputStream类实现的read是即时读取的,即每一次读取都会是一次磁盘IO操作(哪怕只读取了1个字节的数据),可想而知,如果数据量巨大,这样的磁盘消耗非常可怕。而通过缓冲区的实现,读取可以读取缓冲区中的内容,当读取超过缓冲区的内容后再进行一次磁盘IO,载入一段数据填充缓冲,那么下一次读取一般情况下就直接可以从缓冲区读取,减少了磁盘IO。

总结

使用缓冲流好像对于读和写都没有很大的提升,不知道原因在哪里,有知道的朋友评论区一起讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
辉煌互联FTPserver这是一款免费的其特点是易于使用、绿色的(无需安装,只有一个文件)、小巧的的FTP服务器软件。整个FTP服务器就是一个EXE可执行程序,无需任何安装,不修改注册表,删除时直接删除所有相关文件就行了。程序放在任何目录均可运行。可以轻松地将它放在U盘里,邮箱里,网盘里,或者网站上随时下载,这样,就有了一个可以随身携带的FTP服务器软件。。这是一个小巧灵活的FTP服务器工具,占用系统资源少。可快速建立小型的FTP服务器,可以方便应用局域网内用户互相传送文件,不用再为如何另外安装FTP服务器上浪费脑筋。 功能说明: 1、建立便捷FTP服务器。 2、用于局域网,互相点对点传送文件。 3、建立临时FTP服务器,供大家临时下载文件等。 4、提供文件(文件夹)的下载、上传、删除、改名功能。 5、支持多用户访问,可以设置最大连接用户。 6、支持账户/密码访问和权限控制,同样支持匿名访问。 7、配置信息自动保存,下次不用重新输入,用户名清空自动恢复匿名访问。 8、最小化至托盘图标,不占用桌面空间。 9、能设置随系统开机启动。 程序设置: 启动软件后,需要作一些设置: 1. 设置FTP服务器的根目录。以后所有的请求都会以此FTP根目录为基础查找文件。 2. 设置FTP服务器的登录帐号,如果不设置即为允许匿名登录FTP服务器。 3. 设置FTP服务器端口,默认为 21
自己写的ftp服务端程序代码,支持{"USER", do_user }, {"PASS", do_pass }, {"CWD", do_cwd }, {"XCWD", do_cwd }, {"CDUP", do_cdup }, {"REIN", do_rein },//重新初始化,此命令终止USER,重置所有参数,控制连接仍然打开,用户可以再次使用USER命令 {"QUIT", do_quit }, /*------------传输参数命令------------*/ {"PORT", do_port },//数据端口,主要向服务器发送客户数据连接的端口 //格式为PORT h1,h2,h3,h4,p1,p2,其中32位的IP地址用h1,h2,h3,h4表示,16位的TCP端口号用p1,p2表示 {"PASV", do_pasv },//此命令要求服务器数据传输进程在指定的数据端口侦听,进入被动接收请求的状态 {"TYPE", do_type },//文件类型,可指定ASCII码、EBCDIC码、Image、本地类型文件等参数 /*------------服务命令----------------*/ {"RETR", do_retr },//下载文件 {"STOR", do_stor },//上传 {"APPE", do_appe },//上传,如文件已存在,数据附加到尾部 {"REST", do_rest },//重新开始 {"RNFR", do_rnfr }, {"RNTO", do_rnto },//重命名文件或目录 {"ABOR", do_abor },//异常终止 {"DELE", do_dele },//删除文件 {"RMD", do_rmd },//删除目录 {"XRMD", do_rmd }, {"MKD", do_mkd },//新建目录 {"XMKD", do_mkd }, {"PWD", do_pwd },//打印当前目录 {"XPWD", do_pwd }, {"LIST", do_list },//列目录详细清单 {"NLST", do_nlst },//列目录短清单 {"SYST", do_syst },//获取系统信息 {"STAT", do_stat },//返回服务器状态 {"SIZE", do_size },//获得文件大小 {"HELP", do_help }, {"NOOP", do_noop }, {"SITE", do_site }, }等命令

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺着听Jay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值