通过一个文件拷贝案例认识RandomAccessFile

通过一个文件拷贝案例认识RandomAccessFile

RandomAccessFile

  • 它是java.io包下的类,同时实现了DataOutput, DataInput;即可以输入流也可以是输出流。
  • 可以指定位置进行读写操作。(网上很多文件分片上传的案例都是基于该特性实现的。)

并发拷贝的思路描述

1.需求:我有一个大小为(fileSize)150M的视频文件需要复制,准备分给2条线程去执行。
2.根据需求我们很容易想到第一个线程需要复制第0M到75M的字节用数学区间表示为[0,75),第二个线程需要复制[75,150)
多线程拷贝案例图

代码实现

package com.lxh.task;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

public class CopyTask implements Runnable {

    private File source;
    private File copy;
    private long position;
    private CountDownLatch countDownLatch;
    private int bufferSize;

    private long partSize;

    /**
     * @param source 源文件
     * @param copy 复制得到的文件
     * @param position 文件读写位置
     * @param countDownLatch 线程计数器
     * @param bufferSize 缓存区大小
     * @param partSize 分片大小
     */
    public CopyTask(File source, File copy, long position, CountDownLatch countDownLatch, int bufferSize,long partSize) {
        this.source = source;
        this.copy = copy;
        this.position = position;
        this.countDownLatch = countDownLatch;
        this.bufferSize = bufferSize;
        this.partSize = partSize;
    }
    @Override
    public void run() {
        try {
            RandomAccessFile srcRaf = new RandomAccessFile(source,"r");
            RandomAccessFile copyRaf = new RandomAccessFile(copy,"rw");
            srcRaf.seek(position);
            copyRaf.seek(position);
            long begin = System.currentTimeMillis();
            System.out.println(Thread.currentThread().getName()+"从文件位置:"+position+"开始读写操作");
            int len = -1;
            byte[] buffer = new byte[bufferSize];
            long tLen = 0;//记录当前线程读了多数字节
            while ((len=srcRaf.read(buffer))>0){
                copyRaf.write(buffer,0,len);
                tLen+=len;
                if(tLen >= partSize){
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName()+"文件拷贝结束,共拷贝了:"
                    +tLen+ "个字节"+"用时:"+(System.currentTimeMillis()-begin)+"毫秒");
            srcRaf.close();
            copyRaf.close();
            countDownLatch.countDown();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
    @Test
    public void testThreadPoolCopy() throws Exception{
        int threadNum = 2;
        int bufferSize = 1024*8;
        File srcFile = new File("/home/lxq/IdeaProjects/RandomAccesFile/1/150.mp4");
        File copyFile = new File("/home/lxq/IdeaProjects/RandomAccesFile/2/150.mp4");
        long fileSize = srcFile.length();
        long partSize = (fileSize%threadNum==0) ? fileSize/threadNum : fileSize/threadNum+1;
        ExecutorService pool = Executors.newFixedThreadPool(threadNum);
        long begin = System.currentTimeMillis();
        CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        System.out.println(Instant.now() +Thread.currentThread().getName()+"开始复制");
        for(int i=0;i<threadNum;i++){
            pool.submit(new CopyTask(srcFile,copyFile,i*partSize,countDownLatch,bufferSize,partSize));
        }
        countDownLatch.await();
        long end = System.currentTimeMillis();
        System.out.println(Instant.now() +Thread.currentThread().getName()+"复制完成,用时:"+(end-begin)+"毫秒");
    }

代码执行后用diff命令对比,两个文件的二进制有无不一样,如果没有就证明代码运行是成功的。

diff /home/lxq/IdeaProjects/RandomAccesFile/1/150.mp4 /home/lxq/IdeaProjects/RandomAccesFile/2/150.mp4

总结:

  • 通过RandomAccessFile构造方法中指定mode为r或者rw,决定是输出流还是输入流。
  • 通过seek方法可以移动文件指针位置。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值