【Java】用Copy文件例子来描述文件操作

本文探讨了三种不同的Java文件复制方法:逐字节读取、使用缓冲区和使用缓冲区并指定写入长度。通过比较,发现使用缓冲区并指定写入长度的方式在效率和准确性上最佳,避免了数据冗余,实现了与原文件大小一致的复制,且速度快。文章还讨论了缓冲区大小对性能的影响,指出并非越大越好,考虑到IP数据包的限制,适中的缓冲区大小更为合适。
摘要由CSDN通过智能技术生成


  任务要求:准确将一个文件从一个文件夹(resource)复制到另一个文件夹(target)下。

方式一

import java.io.*;

public class Demo1 {
    public static void main(String[] args) {
        File file = new File("resource/sea.mp3");
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            FileOutputStream fileOutputStream = new FileOutputStream("./target/seaCopy.mp3");
            long startTime = System.currentTimeMillis();
            int value = fileInputStream.read();
            /*Copy过程*/
            while(value != -1) {
                fileOutputStream.write(value);
                value = fileInputStream.read();
            }
            long endTime = System.currentTimeMillis();
            System.out.println("用时" + (endTime - startTime) + "毫秒");
            fileInputStream.close();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

/*
输出结果
用时48530毫秒
*/

歌曲是能听的,并且与源文件大小是一模一样的。但是copy时间较长,输出value,每次都是不一样的。

FileInputStream里的

/**
     * Reads a byte of data from this input stream. This method blocks
     * if no input is yet available.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             file is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read() throws IOException {
        return read0();
    }

因为它是逐字节一个个读。

文件3m,时间48s多。这样的速度肯定是我们不能接受的。

方式二

不要一次读一点了,一次性读一段信息。read第二个方法。buffer缓冲区。8k=8*1024,但是想想用位运算不是更好。1<<13。

public int read(byte b[]) throws IOException {
        return readBytes(b, 0, b.length);
    }
import java.io.*;

public class Demo2 {

    public static final int BUFFER_SIZE = 1 << 13;

    public static void main(String[] args) {
        File file = new File("resource/sea.mp3");
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            FileOutputStream fileOutputStream = new FileOutputStream("./target/seaCopy.mp3");
            byte[] buffer = new byte[BUFFER_SIZE];
            long startTime = System.currentTimeMillis();
            int readLen = fileInputStream.read(buffer);
            while (readLen != -1) {
                fileOutputStream.write(buffer);
                readLen = fileInputStream.read(buffer);
            }
            long endTime = System.currentTimeMillis();
            System.out.println("用时" + (endTime - startTime) + "毫秒");
            fileInputStream.close();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

/*结果
用时35毫秒
*/

但是问题出来了,这个文件一定是8k的整数倍吗?不一定吧。所以读到最后就会出现问题了!就会造成不必要的数据冗余,在文件最后面。未被覆盖的倒数第二次数据会被再重复一遍。

用而这种方式写的一定是8k(缓冲区)的整数倍。目标文件不符合我们的最终要求,有多的数据,我们要准准确确的copy版。

方式三

用write三参方式
将buffer数组中的偏移量为第一个参数开始,向后的第二个参数的信息写。读多少写多少!

    /**
     * Writes <code>len</code> bytes from the specified byte array
     * starting at offset <code>off</code> to this file output stream.
     *
     * @param      b     the data.
     * @param      off   the start offset in the data.
     * @param      len   the number of bytes to write.
     * @exception  IOException  if an I/O error occurs.
     */
    public void write(byte b[], int off, int len) throws IOException {
        writeBytes(b, off, len, fdAccess.getAppend(fd));
    }
import java.io.*;

public class Demo3 {

    public static int BUFFER_SIZE = 1 << 13;

    public static void main(String[] args) {
        File file = new File("resource/sea.mp3");
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            FileOutputStream fileOutputStream = new FileOutputStream("./target/seaCopy.mp3");
            byte[] buffer = new byte[BUFFER_SIZE];
            int readLen = 0;
            long startTime = System.currentTimeMillis();
            readLen = fileInputStream.read(buffer);
            while (readLen != -1) {
                fileOutputStream.write(buffer, 0, readLen);
                readLen = fileInputStream.read(buffer);
            }
            long endTime = System.currentTimeMillis();
            System.out.println("用时" + (endTime - startTime) + "毫秒");
            fileInputStream.close();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

/*输出结果
用时12毫秒
*/

并且音乐的Copy版和原版大小一样。我们的要求得到了满足并且速度也快。

缓冲区越大越快,那么缓冲区最好设置多少呢?

IP数据包的最大长度是64KB(65535),对于帧(链路层)来说是1500字节(MTU)。

但是考虑ip数据报报文包含数据报头部信息,因此,实际数据量小于64kb。对于大于64k的数据报文会被路由器切割,切割也是耗时的,不如发小一点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值