【Java基础知识 18】通过FileUtils.copyFile探索IO原理

Java 使用FileUtils.copyFile复制文件 1、FileUtils.copyFile方法 copyFile方法有多种重载形式,下面截图只是其中比较简单的一种,详细见官方文档 2、业务代码: private File copyFile(Long baseTime, int orgId, int typeId, String sourcePath, String fileName) throws IOException { String time = DateUtils.convertDateToString(DateUtils.timesta 阅读详情

一、FileUtils.copyFile

1、从实例出发

一般开发的时候,都是通过文件工具类进行文件的copy,那么它的性能怎么样呢?它是怎么实现的呢?今天就来分析以下FileUtils.copyFile。

private static void copyFileByUtils() {
        String srcFilePath = "H:\\优快云\\JWFS.rar";// 文件大小 68.8 MB
        String destFilePath = "H:\\优快云\\netty\\nio\\JWFS.rar";
        long start = System.currentTimeMillis();

        try {
            FileUtils.copyFile(new File(srcFilePath),new File(destFilePath));
        } catch (IOException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("copyFileByUtils 消耗:"+(end-start)+"毫秒");
    }

在这里插入图片描述

2、还是蛮快的,探索源码一番…

private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
        if (destFile.exists() && destFile.isDirectory()) {
            throw new IOException("Destination '" + destFile + "' exists but is a directory");
        } else {
            FileInputStream fis = null;
            FileOutputStream fos = null;
            FileChannel input = null;
            FileChannel output = null;

            try {
                fis = new FileInputStream(srcFile);
                fos = new FileOutputStream(destFile);
                input = fis.getChannel();
                output = fos.getChannel();
                long size = input.size();
                long pos = 0L;

                for(long count = 0L; pos < size; pos += output.transferFrom(input, pos, count)) {
                    count = size - pos > 31457280L ? 31457280L : size - pos;
                }
            } finally {
                IOUtils.closeQuietly(output);
                IOUtils.closeQuietly(fos);
                IOUtils.closeQuietly(input);
                IOUtils.closeQuietly(fis);
            }

            if (srcFile.length() != destFile.length()) {
                throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile + "'");
            } else {
                if (preserveFileDate) {
                    destFile.setLastModified(srcFile.lastModified());
                }

            }
        }
    }

发现了一个生僻的词汇,FileChannel,研究一下。

二、FileChannel

在这里插入图片描述
这种方式是“在非直接缓冲区中,通过Channel实现文件的复制”。

1、读操作

  1. 将磁盘文件读取到操作系统OS提供的内核地址空间的内存中,第一次复制,OS上下文切换到内核模式;
  2. 将内核地址空间内存中的文件内容复制到JVM提供的用户地址空间的内存中,第二次复制,OS上下文切换到用户模式;

2、写操作

  1. 将用户地址空间的JVM内存中的文件内容复制到OS提供的内核地址空间中的内存中,第一次复制,OS上下文切换到内核模式;
  2. 将内核地址空间中内存的文件内容写入磁盘文件,第二次复制,写入操作完毕后,OS上下文最终切换到用户模式;

JVM控制的内存称为堆内内存,一般用Java操作的内存都属于堆内内存,堆内内存由JVM统一管理,根据上面的流程图可以发现,一次文件的读写要经过4次copy和4次用户控件与内核空间的上下文切换。

3、代码实例

package com.guor.demo.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class CopyFileTest {

    private static void copyFileByChannel() {
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        FileChannel intChannel = null;
        FileChannel outChannel = null;

		String srcFilePath = "H:\\优快云\\JWFS.rar";// 文件大小 68.8 MB
        String destFilePath = "H:\\优快云\\netty\\nio\\JWFS.rar";
        long start = System.currentTimeMillis();

        try {
            fileInputStream = new FileInputStream(srcFilePath);
            fileOutputStream = new FileOutputStream(destFilePath);

            // 获取通道
            intChannel = fileInputStream.getChannel();
            outChannel = fileOutputStream.getChannel();

            // 创建非直接缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (intChannel.read(buffer)!=-1){
                buffer.flip();
                outChannel.write(buffer);
                buffer.clear();
            }
            long end = System.currentTimeMillis();
            System.out.println("copyFileByChannel 消耗:"+(end-start)+"毫秒");
        }catch (Exception e){
            System.out.println(e);
        }finally {
            if(outChannel!=null){
                try {
                    outChannel.close();
                } catch (IOException e) {
                }
            }
            if(intChannel!=null){
                try {
                    intChannel.close();
                } catch (IOException e) {
                }
            }
            if(fileOutputStream!=null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                }
            }
            if(fileInputStream!=null){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                }
            }
        }
    }

    public static void main(String[] args) {
        copyFileByChannel();
    }
}

4、控制台输出

在这里插入图片描述
感觉和FileUtils.copyFile的速度还是有差距的。

三、如何减少copy和上下文切换的次数?

1、为什么不能舍弃内核空间这一步,直接读取到用户空间呢?

因为JVM中有GC,GC会不定期的清理没用的对象,并且压缩文件区域,如果某一时刻正在JVM中复制一个文件,但由于GC的压缩操作可能会引起文件在JVM中的位置发生改变,进而导致程序出现异常。因此,为了保证文件在内存中的位置不发生改变,只能将其放入OS的内存中。

2、如何减少copy和上下文切换的次数?

使用直接缓冲区,就可以在JVM中通过一个address变量指向OS中的一块内存(称为物理映射文件),之后,就可以通过JVM直接使用OS中的内存。

下面介绍一个新的方式“在直接缓冲区中,通过Channel实现文件的复制”。
在这里插入图片描述
这样,数据的赋值操作都是在内核空间里进行的,用户空间与内核空间直接的复制次数为0,也就是零拷贝。

3、代码实例

private static void copyFileByMapped() {

        String srcFilePath = "H:\\优快云\\JWFS.rar";// 文件大小 68.8 MB
        String destFilePath = "H:\\优快云\\netty\\nio\\JWFS.rar";
        long start = System.currentTimeMillis();
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            // 文件的输入通道
            inChannel = FileChannel.open(Paths.get(srcFilePath), StandardOpenOption.READ);
            // 文件的输出通道
            outChannel = FileChannel.open(Paths.get(destFilePath), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);

            // 输入通道和输出通道之间的内存映射文件,内存映射文件处于堆外内存
            MappedByteBuffer inMappedBuffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
            MappedByteBuffer outMappedBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

            // 直接对内存映射文件进行读写
            byte[] bytes = new byte[inMappedBuffer.limit()];
            inMappedBuffer.get(bytes);
            outMappedBuffer.put(bytes);

            long end = System.currentTimeMillis();
            System.out.println("copyFileByMapped 消耗:"+(end-start)+"毫秒");
        }catch (Exception e){
            System.out.println(e);
        }finally {
            try {
                inChannel.close();
                outChannel.close();
            } catch (IOException e) {
            }
        }
    }

4、控制台输出

在这里插入图片描述
直接缓冲区拷贝文件比非直接缓冲区拷贝文件,快了整整10倍。

哪吒精品系列文章

Java学习路线总结,搬砖工逆袭Java架构师

10万字208道Java经典面试题总结(附答案)

SQL性能优化的21个小技巧

Java基础教程系列

Spring Boot 进阶实战
在这里插入图片描述

Java 的几种文件拷贝方式 Files.copy方法在Java中是用来复制文件的一种高级操作,它是基于Java NIO(New Input/Output)的文件API实现的。需要注意的是,在某些操作系统和文件系统中,transferTo 方法可能会限制传输的最大字节数,因此在实际使用中可能需要进行分块传输。使用FileInputStream和FileOutputStream是实现文件拷贝的一种直观且简单的方法,尽管它不如NIO提供的Files.copy方法高效,但在某些情况下仍然非常有用。 阅读详情

相关推荐

Android Bitmap内存优化:从原理到实战的完整解决方案

在移动应用开发中,内存优化是提升应用性能和稳定性的关键技术领域。其核心原理在于理解应用运行时内存的分配、使用与回收机制,特别是针对图片、缓存等资源密集型对象的管理。有效的内存优化技术能显著降低应用崩溃率、提升界面流畅度,并改善多任务环境下的系统资源占用。这一技术在社交、电商、内容浏览等高图片负载的应用场景中价值尤为突出。本文聚焦于Android平台内存消耗的“大户”——Bitmap,深入剖析其Native堆内存模型与开销计算,并详细介绍了通过编译期插桩(AOP)进行无侵入监控,以及利用inSampleSiz

diaocuiguo2493的博客 484

FileUtils copyFile方法 详解~~

一般的方法,我们要复制一个文件,可能需要读取源文件,生成流对象,再写入一个新的文件中,使用apache commons-io很容就可以处理文件的复制。 下面的例子演示我们怎样使用FileUtils.copyFile方法在同一个文件夹复制文件和使用FileUtils.copyFileToDirectory方法复制到指定的文件夹中。其中System.getProperty("java.io.

洪文聊架构 5万+

java 文件移动 常规四种方法 和利用FileCopyUtils.copy( , )方法

使用 java 进行文件拷贝 相信很多人都会用,,不过效率上是否最好呢? 最近看了看NIO决定试一试 java  NIO 到底有什么性能的提升. 第一种方法:古老的方式  public static long forJava(File f1,File f2) throws Exception{   long time=new Date().getTime();   int lengt

一万年太久 - 只争朝夕 2万+

Java常用类(三):FileUtils类

FileUtils类常用方法: 1.复制文件夹 FileUtils.copyDirectory(File srcDir, File destDir) // 复制文件夹(文件夹里面的文件内容也会复制) FileUtils.copyDirectory(File srcDir, File destDir, FileFilter filter) // 复制文件夹,带有文件过滤功能 FileUtils.copyDirectoryToDirectory(File srcDir, File destDir) /.

sulia1234567890的博客 2万+

手把手教你:如何为自制的STM32H7飞控板适配PX4固件(基于NuttX)

本文详细介绍了如何为自制的STM32H7飞控板适配PX4固件,基于NuttX系统进行移植。从硬件设计规范到软件环境配置,再到PX4固件的移植与调试,提供了完整的实战指南。特别分享了如何复用FMU-v6u参考设计以节省开发时间,并解决了常见问题,帮助开发者快速实现高性能飞控系统的搭建。

weixin_27697385的博客 475

ESP32-C61 eFuse控制器深度解析:寄存器架构与安全烧写实践

eFuse(电子熔丝)是嵌入式芯片实现硬件级不可逆配置与信任根构建的核心物理机制,其本质是通过电学编程固化关键安全参数。原理上依赖熔丝单元的单向导通/断开特性,结合Reed-Solomon纠错、多级写保护和时序可控编程,保障数据在宽温域与工艺偏差下的高可靠性。技术价值在于为Secure Boot、Flash加密、密钥隔离等安全功能提供可信锚点,支撑从启动到运行的全链路防护。典型应用场景涵盖物联网设备量产烧录、安全启动使能、MAC地址固化及抗DPA密码运算配置。本文聚焦ESP32-C61平台,深入解析其eFu

weixin_42589700的博客 123

I/O—使用第三方jar包进行io读写

导入第三方jar包 commons-io-2.4.jar maven仓库 <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</ver

weixin_43920664的博客 243

从一个 ASIN 看透亚马逊:商品模型背后的增长飞轮

在亚马逊电商体系中,每件商品背后都有一套严密的商品建模逻辑。本篇文章以“ASIN 的一生”为线索,系统拆解了亚马逊的商品模型:从飞轮战略出发,剖析 SDP(Single Detail Page)机制如何实现标准化展示;再到 ASIN 编码、父子变体结构与 Offer 分离模型,逐层解析商品信息如何被建构、聚合与呈现。通过图解与案例,文章帮助读者理解商品建品流程、同款聚合原则、价格控制机制等核心逻辑,避免常见运营误区,是一份面向运营、产品、技术人员的实用参考指南。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 13万+

[19/04/04-星期四] IO技术_CommonsIO(通用IO,别人造的轮子,FileUtils类 操作文件 & IOUtilsl类 操作里边的内容 )...

一、概念 JDK中提供的文件操作相关的类,但是功能都非常基础,进行复杂操作时需要做大量编程工作。实际开发中,往往需要 你自己动手编写相关的代码,尤其在遍历目录文件时,经常用到递归,非常繁琐。 Apache-commons工具包中提供了IOUtils/FileUtils,可以让我们非常方便的对文件和目录进行操作。 Apache软件基金会(也就...

weixin_30578677的博客 160

PCL 基于视椎体裁剪点云

PCL 基于视椎体裁剪点云

dayuhaitang1的博客 4083

PCL 4PCS算法实现点云粗配准【2026最新版】

博客长期更新,本文最新更新时间为:2026年5月11日。

点云侠的博客 30万+

java批量将gbk编码转化为utf8

http://blog.csdn.net/gaohuanjie/article/details/43736375 http://www.importnew.com/13715.html http://blog.csdn.net/quanzhanjavabiji/article/details/73936240 唉,总算弄好了——项目立项时工程的编码方式为GBK,可是随着研发的不断深入

杨小白er 874

Visual Studio调试技巧与实用方法总结(实战经验分享)

本文根据多年的项目实战经验,详细介绍一些Visual Studio常用的高效调试手段与技巧。

dvlinker的技术专栏 3万+

关于文件复制

一、使用FileStreams复制 这是最经典的方式将一个文件的内容复制到另一个文件中。 使用FileInputStream读取文件A的字节,使用FileOutputStream写入到文件B。 这是第一个方法的代码: 1 private static void copyFileUsingFileStreams(File source, File dest) 2 thr...

zj19930301的博客 422

【SpringBoot 3.x 第92节】Spring Modulith:构建模块化单体架构(基于 Spring Boot 3),一文带你搞透(超详细)!

🏆本文收录于《滚雪球学SpringBoot 3.x》,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。    该专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot3教程导航帖】,你想学习的都被收集在内,快速投入学习!!两不误。

**My Coding Family** 999

【Halcon-2D测量】add_metrology_object_rectangle2_measure 函数功能(用于向2D计量模型中添加旋转矩形(rectangle2类型)计量对象)

HALCON算子add_metrology_object_rectangle2_measure解析摘要 该算子是HALCON 2D计量模块的核心算子,用于添加旋转矩形计量对象并配置测量参数。主要功能包括:定义旋转矩形几何轮廓(中心坐标、主轴角度、长短半长);生成垂直于矩形边界的测量区域;设置边缘提取预处理参数(高斯平滑、振幅阈值)。关键注意事项:MeasureLength1必须小于矩形长短半长;角度参数Phi需使用弧度单位;多线程需同步模型句柄。该算子适用于方形螺母、PCB板边框等矩形零件的精密测量,需与a

weixin_45590420的博客 1223

java复制文件的4种方式

一、使用FileStreams复制 这是最经典的方式将一个文件的内容复制到另一个文件中。 使用FileInputStream读取文件A的字节,使用FileOutputStream写入到文件B。 这是第一个方法的代码: 1 private static void copyFileUsingFileStreams(File source, File dest) ...

weixin_30325793的博客 87

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

基于Java运动器械购物商城设计与实现

本文介绍了一个基于Spring Boot框架开发的运动器械购物商城系统。系统采用Java语言和MySQL数据库,实现了管理员与会员两个角色的功能模块:管理员可进行会员管理、商品分类管理、商品信息管理等操作;会员可浏览商品、加入购物车、下单购买及评价商品。系统设计遵循简洁美观的界面原则,提供高效的数据处理能力,同时注重数据安全性。开发环境包括JDK1.8、Tomcat7服务器、MySQL5.7数据库等工具。核心代码展示了文件上传功能的实现,采用时间戳命名文件并存储在指定目录中,体现了系统的实用性和规范性。

xn19950718的博客 436

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Java课程在线教学平台的设计与实现

如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统Java课程教学信息管理难度大,容错率低,管理人员处理数据费工费时,所以专门为解决这个难题开发了一个Java课程在线教学平台,可以解决许多问题。Java课程在线教学平台实现的功能包括老师管理,教学资源管理,留言板管理,作业管理,公告管理,学生管理等功能。该系统采用了Mysql数据库,Java语言,SSM框架等技术进行编程实现。

xn19950718的博客 391

基于Java的咖啡馆管理系统的设计与实现

本咖啡馆管理系统是建立在B/S模式的基础之上,通过使用idea平台上编写相关的Java代码,实现对系统的功能模块的设计,使用MySQL数据库设计相关的数据表,实现对系统数据资源的管理和控制,使用SSM框架创建相关的项目主流架构,实现系统的基本框架搭建,最后再通过使用Tomcat浏览器将所研发的系统发布到网上,便于相关的用户运行和使用本系统。本系统的实现可以极大地提高相关行业的工作效率,提升用户的使用体验,因此在现实生活中运用本系统具有很大的使用价值。基于Java的咖啡馆管理系统的设计与实现。

xn19950718的博客 448

融汇房地产营销策划有限公司

本文主要描述了该江苏融汇房地产营销策划有限公司的具体开发过程,在SSM框架的基础上,采用vue技术和MYSQL数据库,使该江苏融汇房地产营销策划有限公司具有很好的稳定性和安全性。身处网络时代,随着网络系统体系发展的不断成熟和完善,人们的生活也随之发生了很大的变化,人们在追求较高物质生活的同时,也在想着如何使自身的精神内涵得到提升,而读书就是人们获得精神享受非常重要的途径。该江苏融汇房地产营销策划有限公司不仅能够稳定的运行,快捷方便的操作,界面简洁清晰,而且功能齐全,实用性强。融汇房地产营销策划有限公司。

xn19950718的博客 398

在线电影票购买系统

本文介绍了一个基于Java Web的在线电影票购买系统,采用Spring Boot、Vue和SSM框架,结合MySQL数据库实现。系统提供管理员和用户两种角色功能,包括电影查询、在线购票、选座、评价及订单管理等功能。管理员可更新电影信息和管理订单,用户能便捷购票。系统运用Java面向对象特性和MySQL高效数据处理能力,简化开发流程并确保稳定性。通过Idea开发环境实现,提供了部分功能效果截图和核心文件上传代码示例。该项目旨在为现代用户提供便捷的在线购票体验,满足影院售票管理需求。

xn19950718的博客 602

购物商场的设计与实现

因此,在计算机上安装购物商场软件来发挥其高效地信息处理的作用,可以规范信息管理流程,让管理工作可以系统化和程序化,同时,购物商场的有效运用可以帮助管理人员准确快速地处理信息。购物商场在对开发工具的选择上也很慎重,为了便于开发实现,选择的开发工具为Eclipse,选择的数据库工具为Mysql。以此搭建开发环境实现购物商场的功能。购物商场是一款运用软件开发技术设计实现的应用系统,在信息处理上可以达到快速的目的,不管是针对数据添加,数据维护和统计,以及数据查询等处理要求,购物商场都可以轻松应对。

xn19950718的博客 460

宿舍管理系统

本文摘要: 宿舍管理系统是基于Spring Boot框架和MySQL数据库开发的现代化信息管理平台,旨在解决传统纸质管理模式效率低下的问题。系统采用Java语言开发,充分利用其面向对象特性(封装、继承、多态)和Spring Boot的自动化配置优势,实现了宿舍信息管理、评分管理、来访登记、维修登记等核心功能。通过MySQL数据库的高效数据操作能力,系统显著提升了信息处理的规范性和查询效率,支持绿色无纸化办公。开发过程涵盖了完整软件生命周期,包括需求分析、系统设计、编码实现和测试验证。系统界面友好(如图片所示

xn19950718的博客 383

校园二手交易平台

本系统针对校园二手商品的交易而开发,提供管理员、用户、商家三种角色的服务。总的功能包括商品的查询、商品的购买、购物车管理和订单管理。本系统可以帮助管理员审核商品信息和管理用户(商家、普通用户)信息,帮助用户实现在线的购买方式,并可以实现订单管理。社会和科技的不断进步带来更便利的生活,计算机技术也越来越平民化。二十一世纪是数据时代,各种信息经过统计分析都可以得到想要的结果,所以也可以更好的为人们工作、生活服务。如果可以把计算机技术和二手商品销售相结合更符合现代、用户的要求,实现更为方便的购买商品的方式。

xn19950718的博客 430

明嘉新材料公司仓库管理系统的设计与实现

本文设计并实现了一款基于SSM框架的明嘉新材料公司仓库管理系统,旨在解决传统人工管理模式的效率低下问题。系统采用B/S架构,使用Java语言开发,结合Spring Boot简化配置,MySQL数据库存储数据,Tomcat作为服务器。系统具备仓库信息管理、数据更新与保存等功能,通过模块化设计提高了企业工作效率。文章详细阐述了系统需求分析、技术选型、功能实现及测试过程,并展示了主要功能界面。该系统显著减少了人力物力消耗,具有较高的实用价值。

xn19950718的博客 419
上一篇: 传统关系型数据库和NoSQL数据库有何区别?
下一篇: NoSQL数据库进阶实战 2,NoSQL数据存储模式
哪 吒
哪 吒 2022年度博客之星TOP 1 2022年度博客之星TOP 1 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 59万+粉丝 2943原创
评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

哪 吒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值