1. 程式人生 > >RandomAccessFile多執行緒下載檔案

RandomAccessFile多執行緒下載檔案

原理:

RandomAccessFile能夠隨機讀取檔案,可以讀寫指定位置的內容。所以我們可以開啟n個下載執行緒,每個執行緒專門負責檔案中的一段,當然下載也同樣只是下載對應段的內容。

那怎麼從網路上獲取檔案的特定段呢?
http 1.1提供了分段下載的功能,只需要設定好請求頭就好了,如下:
conn.setRequestProperty(“Range”, “bytes=” + StartPos + “-” + EndPos);
請求的檔案段為 [StartPos, EndPos] 。

RandomAccessFile類的常用方法:

  • public RandomAccessFile(File file, String mode)throws FileNotFoundException 構造方法 接收File類的物件,指定操作路徑,但是在設定時需要設定模式:”r”: 只讀、”w”: 只寫、”rw”: 讀寫。
  • public RandomAccessFile(String name, String mode) throws FileNotFoundException 構造方法 不再使用File類物件表示檔案,而是直接輸入了一個固定的檔案路徑。
  • public void close() throws IOException 關閉操作
  • public int read(byte[] b) throws IOException 將內容讀取到一個byte陣列之中
  • public final byte readByte() throws IOException 讀取一個位元組
  • public final int readInt() throws IOException從檔案中讀取整型資料。
  • public void seek(long pos) throws IOException 設定讀指標的位置。
  • public final void writeBytes(String s) throws IOException 將一個字串寫入到檔案之中,按位元組的方式處理。
  • public final void writeInt(int v) throws IOException 將一個int型資料寫入檔案,長度為4位。
  • public int skipBytes(int n) throws IOException 指標跳過多少個位元組。

程式碼實現:

DownloadFile.class

/***
 * 要十分注意StartPos 和 EndPos 設定
 * ***/
public class DownloadFile {
    public final static String FileURL = "http://apache.01link.hk/tomcat/tomcat-7/v7.0.86/bin/apache-tomcat-7.0.86.zip";
    public final static int COUNT = 3;      //分段數
    public static File SaveFile;

    public static void main(String[] args) throws IOException {
        URL url = new URL(FileURL);
        //建立一個連線
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setRequestMethod("GET");
        conn.connect();
        int code = conn.getResponseCode();
        int position = FileURL.lastIndexOf("/");
        String fileName = FileURL.substring(position+1);   //檔名
        System.out.println("file name is :"+fileName);
        if(code == 200){
            int FileLength = conn.getContentLength();  //獲取檔案長度
            System.out.println("檔案總長度為:"+FileLength);

            SaveFile = new File("/home/pzs/husin/filedownload/"+fileName);
            RandomAccessFile raf = new RandomAccessFile(SaveFile,"rw"); //若沒有該檔案,則自動建立
            raf.setLength(FileLength);  //設定檔案長度
            raf.close();

            //分塊大小
            int blockSize = FileLength / COUNT;
            for(int i=0; i <= COUNT; i++){
                int StartPos = i * blockSize;
                int EndPos = (i+1) * blockSize - 1;

                //最後一條執行緒EndPos = FileLength
                if(i == COUNT){
                    EndPos = FileLength;
                }
                System.out.println("執行緒" + i + "下載的部分為:" + StartPos +"---" + EndPos);
                new DownLoadThread(i,StartPos,EndPos,FileURL,SaveFile).start();
            }

        }
    }
}

DownLoadThread.class

public class DownLoadThread extends Thread{
    //執行緒id
    private int threadId;
    private int StartPos;
    private int EndPos;
    private String FileURL;
    private File SaveFile;

    public DownLoadThread(int threadId, int StartPos, int EndPos, String FileURL, File SaveFile){
        this.threadId = threadId;
        this.StartPos = StartPos;
        this.EndPos = EndPos;
        this.FileURL = FileURL;
        this.SaveFile = SaveFile;
    }

    @Override
    public void run() {
        try {
            URL url = new URL(FileURL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(500);
            conn.setRequestMethod("GET");
            //請求檔案段
            conn.setRequestProperty("Range", "bytes=" + StartPos + "-" + EndPos);
            int code = conn.getResponseCode();
            //206表示檔案分段請求,而不是整個檔案請求
            if(code == 206){
                InputStream is = conn.getInputStream();
                int len = 0;
                byte[] buf = new byte[1024];
                RandomAccessFile raf = new RandomAccessFile(SaveFile, "rw");
                raf.seek(StartPos);
                while((len = is.read(buf)) > 0) {
                    raf.write(buf, 0, len);
                }
                is.close();
                System.out.println("執行緒" + threadId + "下載完畢!!");
            }else{
                System.out.println("不支援分段下載");
            }

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

這裡寫圖片描述

這裡寫圖片描述