java文件拷贝方式

 

java文件拷贝方式

java.io提供了FileInputStream、FileOutputStream文件拷贝方式


public static void copyFileByStream(File source, File dest) throws
        IOException {
    try (InputStream is = new FileInputStream(source);
         OutputStream os = new FileOutputStream(dest);){
        byte[] buffer = new byte[1024];
        int length;
        while ((length = is.read(buffer)) > 0) {
            os.write(buffer, 0, length);
        }
    }
 }

java.nio提供transferTo,transferFrom可进行文件拷贝方式


public static void copyFileByChannel(File source, File dest) throws
        IOException {
    try (FileChannel sourceChannel = new FileInputStream(source)
            .getChannel();
         FileChannel targetChannel = new FileOutputStream(dest).getChannel
                 ();){
        for (long count = sourceChannel.size() ;count>0 ;) {
            long transferred = sourceChannel.transferTo(
                    sourceChannel.position(), count, targetChannel);            sourceChannel.position(sourceChannel.position() + transferred);
            count -= transferred;
        }
    }
 }

nio提供的transferTo,transferFrom的文件拷贝方式更为高效,其采用zero-copy技术

拷贝实现机制

首先需要理解用户态空间(user-space)和内核态空间(kernal-space),操作系统内核、硬件驱动等运行在内核态空间,具有相对高的特权;而用户态空间,则是给普通应用和服务使用。

没有使用zero-copy技术的文件拷贝图:

其流程:1.将文件从磁盘复制到kernel,2.kernel-space拷贝到user-space,3,用户user-space复制到kernel,4.kernel复制到磁盘

而使用zero-copy技术:

其流程:1.将文件从磁盘复制到kernel,2,senderkernel->accepter kernel,3.kernel复制到磁盘

减少了Io传输,减少了CPU切换,从而加快文件拷贝

Java IO/NIO源码分析

Java 标准库也提供了文件拷贝方法(java.nio.file.Files.copy),copy 不仅仅是支持文件之间操作

private static long copy(InputStream source, OutputStream sink)
      throws IOException

public static Path copy(Path source, Path target, CopyOption... options)
  throws IOException

public static long copy(InputStream in, Path target, CopyOption... options)
  throws IOException

public static long copy(Path source, OutputStream out) 
throws IOException

copy 方法其实不是利用 transferTo,而是本地技术实现的用户态拷贝。

如何提高类似拷贝等 IO 操作的性能,有一些宽泛的原则:

  • 使用缓存等机制,合理减少 IO 次数
  • 使用 transferTo 等机制,减少上下文切换和额外io
  • 尽量减少不必要的转换过程,比如编解码;对象序列化和反序列化
public static Path copy(Path source, Path target, CopyOption... options)
    throws IOException
 {
    FileSystemProvider provider = provider(source);
    if (provider(target) == provider) {
        // same provider
        provider.copy(source, target, options);// 这是本文分析的路径
    } else {
        // different providers
        CopyMoveHelper.copyToForeignTarget(source, target, options);
    }
    return target;
}

NIO源码

Buffer 是 NIO 操作数据的基本工具,Java 为每种原始数据类型都提供了相应的 Buffer 实现(布尔除外)。

Buffer 有几个基本属性:

  • capcity,它反映这个 Buffer 到底有多大,也就是数组的长度
  • position,要操作的数据起始位置。
  • limit,相当于操作的限额。在读取或者写入时,limit 的意义不一样,
    -mark,记录上一次 postion 的位置,默认是 0,算是一个便利性的考虑,往往不是必须的。

Buffer 的基本操作:

  • 我们创建了一个 ByteBuffer,准备放入数据,capcity 当然就是缓冲区大小,而 position 是 0,limit 默认就是 capcity 的大小。
  • 当我们写入几个字节的数据时,position 就会跟着水涨船高,但是它不可能超过 limit 的大小。
  • 如果我们想把前面写入的数据读出来,需要调用 flip 方法,将 position 设置为 0,limit 设置为以前的 position 那里。
  • 如果还想从头再读一遍,可以调用 rewind,让 limit 不变,position 再次设置为 0。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值