亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在Java中利用多線程實現分片下載文件

發布時間:2021-04-15 17:58:41 來源:億速云 閱讀:493 作者:Leah 欄目:編程語言

這期內容當中小編將會給大家帶來有關怎么在Java中利用多線程實現分片下載文件,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

1、如何請求才能拿到數據的特定部分,而非全部?

可以在HTTP請求頭中加入Range來標識數據的請求范圍/區間,從HTTP/1.1開始可用。

基本用法:

Range: bytes=10-:取第10個字節及后所有數據。

Range: bytes=40-100:取第40個字節到第100個字節之間的數據。

這樣我們就能拿到特定部分的數據了,斷點續傳也可以用這個來實現。

PS:0為開始點。

2、分片后某線程下載時如何寫出?

思路1:等所有下載完成后進行統一匯總整理然后再一次性寫出。

這簡直是最笨的思路了,如果文件過大全部拉到內存中,豈不涼涼。

思路2:下載采用多線程,寫出時采取數據前后順序排隊寫出。

也就是說多線程下載,單線程輸出,某種程度解決了內存占用問題,不過效率基本不理想。

思路3:要說還是API香,老大哥Java給我們提供了一個類叫做RandomAccessFile。

這個類可以進行隨機文件讀寫,其中有一個seek函數,可以將指針指向任意位置,然后進行讀寫。什么意思呢,舉個栗子:假如我們開了30個線程,首先第一個下載完成的是線程X,它下載的數據范圍是4000-9000,那么這時我們調用seek函數將指針撥動到4000,然后調用它的write函數將byte寫出,這時4000之前都是NULL,4000之后就是我們插入的數據。這樣就可以實現多線程下載和本地寫入了。

具體實現

一個分片下載類,我們需要創建多個對象來進行下載。

public class UnitDownloader implements Runnable {
  private int from;
  private int to;
  private File target;
  private String uri;
  private int id;

  public UnitDownloader(int from, int to, File target, String uri, int id) {
    this.from = from;
    this.to = to;
    this.target = target;
    this.uri = uri;
    this.id = id;
  }

  public int getFrom() {
    return from;
  }

  public int getTo() {
    return to;
  }

  @Override
  public void run() {
    //download and save data
    try {
      HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
      connection.setRequestProperty("Range", "bytes=" + from + "-" + to);
      connection.connect();
      int totalSize = connection.getContentLength();
      InputStream inputStream = connection.getInputStream();
      RandomAccessFile randomAccessFile = new RandomAccessFile(target, "rw");
      randomAccessFile.seek(from);
      byte[] buffer = new byte[1024 * 1024];
      int readCount = inputStream.read(buffer, 0, buffer.length);
      while (readCount > 0) {
        totalSize -= readCount;
        System.out.println("分片:" + this.id + "的剩余:" + totalSize);
        randomAccessFile.write(buffer, 0, readCount);
        readCount = inputStream.read(buffer, 0, buffer.length);
      }
      inputStream.close();
      randomAccessFile.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

分片下載管理器,主要就是拿到內容的總大小,將其分配給每一個UnitDownloader。這里的threadCount函數可以再考慮優化一下。

public class MultipleThreadDownloadManager implements Runnable {
  private String uri;
  private File target;

  public MultipleThreadDownloadManager(String uri, File target) {
    this.target = target;
    this.uri = uri;
    if (target.exists() == false) {
      try {
        target.createNewFile();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * 開始下載
   */
  public void start() {
    new Thread(this).start();
  }


  /**
   * 根據文件總大小計算線程數量
   *
   * @param totalSize
   * @return
   */
  public int threadCount(int totalSize) {
    if (totalSize < 30 * 2014 * 1024) {
      return 1;
    }
    return 30;
  }


  @Override
  public void run() {
    //獲取文件總大小
    int totalSize = 0;
    try {
      HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
      connection.connect();
      int contentLength = connection.getContentLength();
      totalSize = contentLength;
    } catch (IOException e) {
      e.printStackTrace();
    }
    //將文件分片并分開下載
    int threadCount = threadCount(totalSize);
    int perThreadSize = totalSize / threadCount;//每一個線程分到的任務下載量
    int id = 0;
    int from = 0, to = 0;
    while (totalSize > 0) {
      id++;
      //計算分片
      if (totalSize < perThreadSize) {
        from = 0;
        to = totalSize;
      } else {
        from = totalSize;
        to = from + perThreadSize;
      }
      //開始下載
      UnitDownloader downloader = new UnitDownloader(from, to, target, uri, id);
      new Thread(downloader).start();
    }
  }
}

上述就是小編為大家分享的怎么在Java中利用多線程實現分片下載文件了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

张家港市| 四平市| 安吉县| 赣榆县| 深水埗区| 博乐市| 新平| 澳门| 凉山| 基隆市| 华池县| 蓬溪县| 常宁市| 诸城市| 鸡西市| 黄龙县| 靖宇县| 武冈市| 太白县| 万荣县| 习水县| 于田县| 文水县| 永新县| 紫金县| 湖南省| 汝阳县| 罗田县| 汶上县| 济南市| 庆元县| 盘山县| 元江| 宜君县| 遵义县| 株洲县| 明水县| 台安县| 南丹县| 南安市| 邯郸县|