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
相關文章
相關標籤/搜索