java-copy文件效率的探究

java-copy文件效率的探究

1.字节流和缓冲流

我们需要了解一个知识,就是字节流FileInputStream 和 缓冲流.BufferedInputStream 这两个区别.

下面这段代码是字节流的copy文件示例.

import java.io.*;
public class CopyFile {
    public static void main(String[] args) {
        try {
            // Create a byte stream to read from the source file
            FileInputStream fis = new FileInputStream("source.txt");
            // Create a byte stream to write to the destination file
            FileOutputStream fos = new FileOutputStream("destination.txt");
            // Read bytes from the source file and write them to the destination file
            int b;
            while ((b = fis.read()) != -1) {
                fos.write(b);
            }
            // Close the streams
            fis.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

下面这段代码是缓冲流的copy文件示例.

import java.io.*;
public class CopyFile {
    public static void main(String[] args) {
        try {
            // Create a buffered stream to read from the source file
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.txt"));
            // Create a buffered stream to write to the destination file
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("destination.txt"));
            // Read bytes from the source file and write them to the destination file
            int b;
            while ((b = bis.read()) != -1) {
                bos.write(b);
            }
            // Close the streams
            bis.close();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

可以看到字节流和缓冲流的表面上区别就是缓冲流在字节流之上包装了一个Buffered.但是他们本质上的运行原理是不一样的.

字节流每读一个字节,都是cpu去访问文件,而缓冲流却是先将文件的部分(默认8M)缓冲到内存里面,缓冲流每读一个字节,是cpu去访问内存.

在文件相对大的情况下,一个是访问内存,一个是访问磁盘,它们的效率不可同日而语.

或许上述的描述不太准确,因为我们都见过byte b = new byte[8192]这样的代码.不管是字节流或者说缓冲流都会这样使用,那么如果要使用数组接受,描述应该是这样的:

字节流每读一个数组,都是cpu去访问文件,而缓冲流却是先将文件的部分(默认8M)缓冲到内存里面,缓冲流每读一个数组,是cpu去访问内存.

即使如此,它们的效率也是不可同日而语.

我们的结论是:

缓冲流的效率高于字节流

如果文件很小,反而字节流的效率要高.因为构造缓冲区本身还需要一定资源的.

2.FileUtil工具类

如果是copy文件,那么每次都要写上述的代码,那就很繁琐,所以我们就有了工具类,但是不同的工具类底层到底是字节流还是缓冲流,我们需要探究下,来选择我们所需要的.

  • org.springframework.util.FileCopyUtils
    可以追溯源码,到StreamUtils里面
    public static int copy(InputStream in, OutputStream out) throws IOException {
        Assert.notNull(in, "No InputStream specified");
        Assert.notNull(out, "No OutputStream specified");
        int byteCount = 0;

        int bytesRead;
        for(byte[] buffer = new byte[4096]; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
            out.write(buffer, 0, bytesRead);
        }

        out.flush();
        return byteCount;
    }

这里面InputStream是ChannelInputStream,就是字节流,尽管有4096的数组.

  • cn.hutool.core.io.FileUtil
    往下追溯,一般会走到系统的native的copy里面,系统的函数一般是有缓冲区的
private static native void CopyFileEx0(long existingAddress, long newAddress,
        int flags, long addressToPollForCancel) throws WindowsException;
  • org.apache.commons.io.FileUtil
    与上一个一样,也是走的系统的函数.
private static native void CopyFileEx0(long existingAddress, long newAddress,
        int flags, long addressToPollForCancel) throws WindowsException;

那么很明显得出结论:FileCopyUtils的效率不高.

3.系统的函数

系统的cp都是调用系统的copy函数

剪切 会调用move函数 或者rename函数.
值得注意的是:File.renameTo底层就是系统的rename函数.rename函数可能会直接修改名字/位置.那么在相同磁盘的剪切非常快速,底层使用的就是rename函数.只是修改目录和名字而已,但是不同磁盘的却是需要copy移动,所以速度就慢了下来.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值