java 用RandomAccessFile实现多线程断点续传(拷贝)

  1. 首先看RandomAccessFile类的api说明:
    • 该类的实例支持读取和写入随机访问文件。 随机访问文件的行为相似于存储在文件系统中的大量字节。 有一种游标,或索引到隐含的数组,称为 文件指针 ; 输入操做读取从文件指针开始的字节,并使文件指针超过读取的字节。 若是在读/写模式下建立随机访问文件,则输出操做也可用; 输出操做从文件指针开始写入字节,并将文件指针提早到写入的字节。 写入隐式数组的当前端的输出操做会致使扩展数组。 文件指针能够经过读取 getFilePointer方法和由设置 seek方法。
    • 大意就是把文件当作数组,经过下标去读写,该下标便是咱们所说的文件指针。能够经过上述的两种方法去获取、设置文件指针所指的位置。
  2. 断点续传的思路:
    • 既然能够设置指针的位置,那么咱们能够记录下当前拷贝到的位置,当程序意外中断或者暂停从新运行后,再去读取以前记录位置的值,设置文件指针到该位置以达到继续传输而不是从头开始的效果。
    • 问题:怎么保存指针位置值?
    •            因为程序结束后全部值都会从内存中清除,只能经过外部值来存储,第一种是:单线程拷贝下将指针设置为已拷贝文件的长度(length),多线程下是不可行的,由于多个线程在同时写入一个目标文件,没法获取到每个分段已拷贝的大小。第二种是:文件指针存储到文件中。
  3. 本例需求:
    • 采用多线程技术,实现多线程断点续传,要求线程的数量可由客户端程序来设置

//Test01前端

package com.wxg.download_threads;

import java.io.File;
import java.util.Scanner;

public class Test01 {

    public static void main(String[] args) throws Exception {
        File sourceFile=new File("性感荷官在线发牌.avi");
        File targetFile=new File("copy.avi");
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入须要启动的线程数量(最多8个)");
        int copyNum=scan.nextInt();
        scan.close();
        if(copyNum>8||copyNum<=0){
            System.out.println("输入错误");
            return;
        }

        long copySize=sourceFile.length()/copyNum;//计算前copyNum-1个线程拷贝文件的分段大小
        int i;
        for(i=0;i<copyNum-1;i++){
            new DownloadUtilThreads(sourceFile, targetFile, copySize, copySize*i).start();
        }
        new DownloadUtilThreads(sourceFile, targetFile, copySize+(sourceFile.length()%copyNum), copySize*(i+1)).start();
        
    }
}
View Code

//拷贝线程:DownloadUtilThreadsjava

package com.wxg.download_threads;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;

public class DownloadUtilThreads extends Thread {

    private long copySize;
    private long point;
    private RandomAccessFile r;
    private RandomAccessFile w;
    private File logFile;


    public DownloadUtilThreads(File sourceFile,File targetFile,long copySize,long point) throws FileNotFoundException {
        this.copySize=copySize;
        this.point=point;
        r=new RandomAccessFile(sourceFile, "r");
        w=new RandomAccessFile(targetFile, "rw");
    }


    @Override
    public void run() {
        try {
            //建立日志操做对象
            logFile=new File(Thread.currentThread().getName()+"_download.log");
            LogOpreator logOpreator = new LogOpreator(logFile);

            //首次启动下载
            if(logFile.length()==0){
                logOpreator.write(point,false);
            }
            //读取日志文件取出point,isFinish
            long startIndex = logOpreator.readPoint();
            boolean isFinish = logOpreator.readIsFinish();
            System.out.println(startIndex+"---"+isFinish);
            
            //判断是否已经下载完成
            if(isFinish){
                return;
            }
            
            //设置指针偏移
            r.seek(startIndex);
            w.seek(startIndex);

            //拷贝            
            byte[] b=new byte[8192];
            int len;            
    

            while((len=r.read(b))!=-1){
                w.write(b, 0, len);
                
                startIndex+=len;
                logOpreator.write(startIndex,false);
                
                //判断拷贝是否完成
                if(startIndex>=copySize){
                    logOpreator.write(startIndex,true);
                    System.out.println(startIndex+"---"+isFinish);
                    break;
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
DownloadUtilThreads.java

//实体存储对象:DownloadLog(其中point用于存储文件指针,isFinish用于存储文件是否拷贝完)api

package com.wxg.download_threads;

import java.io.Serializable;

public class DownloadLog implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private long point;
    private boolean isFinish=false;
    
    
    
    public DownloadLog() {

    }

    public DownloadLog(long point,boolean isFinish) {
        this.point = point;
        this.isFinish=isFinish;
    }

    public long getPoint() {
        return point;
    }

    public void setPoint(long point) {
        this.point = point;
    }

    @Override
    public String toString() {
        return "DownloadLog [point=" + point + "]";
    }

    public boolean isFinish() {
        return isFinish;
    }

    public void setFinish(boolean isFinsh) {
        this.isFinish = isFinsh;
    }
    
    
}
DownloadLog.java

//日志读写操做:LogOpreator数组

package com.wxg.download_threads;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class LogOpreator {

    private DownloadLog d;
    private ObjectInputStream obi;
    private ObjectOutputStream obo;
    private File file;


    public LogOpreator(File file) {
        this.file = file;
    }

    //写入对象到文件
    public void write(long point,boolean isFinish){
        d=new DownloadLog(point,isFinish);
        try {
            obo=new ObjectOutputStream(new FileOutputStream(file));
            obo.writeObject(d);
            obo.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    //取出point
    public long readPoint(){
        try {
            obi=new ObjectInputStream(new FileInputStream(file));
            Object logOb = obi.readObject();
            DownloadLog log=(DownloadLog)logOb;
            obi.close();
            return log.getPoint();
        } catch (Exception e) {

            e.printStackTrace();
        }

        return 0;        
    }
    public boolean readIsFinish(){
        try {
            obi=new ObjectInputStream(new FileInputStream(file));
            Object logOb = obi.readObject();
            DownloadLog log=(DownloadLog)logOb;
            obi.close();
            return log.isFinish();
        } catch (Exception e) {

            e.printStackTrace();
        }
        return false;    
    }

}
LogOpreator.java
相关文章
相关标签/搜索