2013-03-11 36 views
19

我試圖在我的下載管理器中實現暫停/恢復,我在網上搜索並閱讀了幾篇文章,並根據它們更改我的代碼,但恢復似乎無法正常工作,任何想法?在文件下載中執行暫停/恢復

   if (!downloadPath.exists()) 
        downloadPath.mkdirs(); 

       if (outputFileCache.exists()) 
       { 
        downloadedSize = outputFileCache.length(); 
        connection.setAllowUserInteraction(true); 
        connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-"); 
        connection.setConnectTimeout(14000); 
        connection.connect(); 
        input = new BufferedInputStream(connection.getInputStream()); 
        output = new FileOutputStream(outputFileCache, true); 
        input.skip(downloadedSize); //Skip downloaded size 
       } 
       else 
       { 
        connection.setConnectTimeout(14000); 
        connection.connect(); 
        input = new BufferedInputStream(url.openStream()); 
        output = new FileOutputStream(outputFileCache); 
       } 

       fileLength = connection.getContentLength();     


       byte data[] = new byte[1024]; 
       int count = 0; 
       int __progress = 0; 
       long total = downloadedSize; 

       while ((count = input.read(data)) != -1 && !this.isInterrupted()) 
       { 
        total += count; 
        output.write(data, 0, count); 
        __progress = (int) (total * 100/fileLength); 

       } 
       output.flush(); 
       output.close(); 
       input.close(); 
+1

究竟是不是工作? – BrianPlummer 2013-03-11 21:47:58

+0

@BrianPlummer當我暫停並繼續下載時,下載從開始開始,並在到達最後狀態時被鎖定,我暫停它。 – NullPointer 2013-03-11 21:52:38

+0

@BrianPlummer我覺得這行'(int)(total * 100/fileLength)'返回錯誤的進度! – NullPointer 2013-03-14 15:50:54

回答

17

好固定的問題,這是我對其他用戶的代碼誰願意來實現暫停/恢復:

 if (outputFileCache.exists()) 
     { 
      connection.setAllowUserInteraction(true); 
      connection.setRequestProperty("Range", "bytes=" + outputFileCache.length() + "-"); 
     } 

     connection.setConnectTimeout(14000); 
     connection.setReadTimeout(20000); 
     connection.connect(); 

     if (connection.getResponseCode()/100 != 2) 
      throw new Exception("Invalid response code!"); 
     else 
     { 
      String connectionField = connection.getHeaderField("content-range"); 

      if (connectionField != null) 
      { 
       String[] connectionRanges = connectionField.substring("bytes=".length()).split("-"); 
       downloadedSize = Long.valueOf(connectionRanges[0]); 
      } 

      if (connectionField == null && outputFileCache.exists()) 
       outputFileCache.delete(); 

      fileLength = connection.getContentLength() + downloadedSize; 
      input = new BufferedInputStream(connection.getInputStream()); 
      output = new RandomAccessFile(outputFileCache, "rw"); 
      output.seek(downloadedSize); 

      byte data[] = new byte[1024]; 
      int count = 0; 
      int __progress = 0; 

      while ((count = input.read(data, 0, 1024)) != -1 
        && __progress != 100) 
      { 
       downloadedSize += count; 
       output.write(data, 0, count); 
       __progress = (int) ((downloadedSize * 100)/fileLength); 
      } 

      output.close(); 
      input.close(); 
     } 
+0

爲什麼你要設置'connection.setAllowUserInteraction(true);'?文件說:'設置allowUserInteraction。 Android未使用'。你爲什麼需要它? – felixd 2013-12-18 14:24:39

+1

實際問題是什麼? – 2014-02-19 05:41:16

+3

@NullPointer,你如何初始化'outputFileCache'? – 2015-01-18 08:54:20

4

這是不可能告訴什麼是錯的沒有一些更多的信息,但是要注意的事情:

  1. 你必須做一個HTTP/1.1請求(很難從你的示例代碼來告訴)
  2. 服務器必須支持HTTP/1.1
  3. 服務器將告訴你它支持一個Accept-範圍的響應
  4. 頭如果-範圍應該是服務器給你的資源的eTag,不是最後修改的時間

您應該檢查與一些簡單的測試起源實際上支持範圍請求第一(如捲曲或wget的)

1

我會從這條線開始調試您的範圍要求:

connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-"); 

從源代碼中無法確定什麼是downloadedSize,這很難進一步闡述,但格式應該是bytes=from-to

無論如何,我建議你使用Apache HttpClient來避免常見的陷阱。 Here是使用Apache HttpClient處理類似主題的人的問題,並提供了一些示例代碼。

0

我想你只需要刪除input.skip(downloadedSize)一行。設置字節範圍的HTTP頭意味着服務器將跳過發送這些字節。

假設您有一個由「aaaaabbbbbcccccddddd」組成的長度爲20個字節的文件,並且假設傳輸在下載5個字節後暫停。然後Range標題將導致服務器發送「bbbbbcccccddddd」,您應該閱讀全部這個內容並將其附加到文件 - no skip()。但是,代碼中的skip()調用將跳過「bbbbb」,而將「cccccddddd」保留下來。如果您已經下載了至少50%的文件,那麼skip()會耗盡所有輸入,並且什麼都不會發生。

此外,stringy05的所有帖子的帖子適用。您應該確保服務器支持HTTP/1.1,確保資源支持Range標頭(動態生成的內容可能不支持該標頭),並確保使用etag和修改日期修改資源。

+0

試過但沒有改變任何東西。 – NullPointer 2013-03-21 11:32:36

2

這不可能是您的服務器需要很長時間才能響應(超過了超時限制),或者這並非所有服務器都支持暫停 - 恢復。 這也是一個需要思考的問題,即通過Http,https,ftp或udp下載文件的天氣。

暫停「可能意味着讀取一些流並將其寫入磁盤。恢復時,您必須使用標題指定要下載的內容

,你可以嘗試這樣的:

HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
    if(ISSUE_DOWNLOAD_STATUS.intValue()==ECMConstant.ECM_DOWNLOADING){ 
     File file=new File(DESTINATION_PATH); 
     if(file.exists()){ 
      downloaded = (int) file.length(); 
     connection.setRequestProperty("Range", "bytes="+(file.length())+"-"); 
    } 
}else{ 
    connection.setRequestProperty("Range", "bytes=" + downloaded + "-"); 
} 
connection.setDoInput(true); 
connection.setDoOutput(true); 
progressBar.setMax(connection.getContentLength()); 
in = new BufferedInputStream(connection.getInputStream()); 
fos=(downloaded==0)? new FileOutputStream(DESTINATION_PATH): new FileOutputStream(DESTINATION_PATH,true); 
bout = new BufferedOutputStream(fos, 1024); 
byte[] data = new byte[1024]; 
int x = 0; 
while ((x = in.read(data, 0, 1024)) >= 0) { 
    bout.write(data, 0, x); 
    downloaded += x; 
    progressBar.setProgress(downloaded); 
} 

,並請嘗試同步的東西。

+0

不要使用'connection.setDoInput(true);'和'connection.setDoOutput(true);',這會導致另一個問題。 – NullPointer 2013-03-21 11:35:38

+0

如果要發送(輸出)請求正文,例如POST或PUT請求,則需要將其設置爲true。通過GET,你通常不會發送一個身體,所以你不需要它。 與接收傳入響應的主體類似,您需要將輸入設置爲true。 通過連接的輸出流發送請求正文本身: conn.getOutputStream()。write(someBytes); – 2013-03-21 13:20:48

+0

我不認爲 '__progress =(int)(total * 100/fileLength);' 做錯了什麼 – 2013-03-21 13:25:47