2013-07-01 29 views
4

我有一款適用於Android的應用程序,可從互聯網下載數百個文件。下載後一些文件變爲0字節。該應用程序嘗試檢測這些情況並在下載後刪除這些文件,但有時會失敗。這個問題在Android 4.x設備上更頻繁。在Android上下載文件時未檢測到0字節文件

這裏是下載的方法。我從inputStream.read(buffer)獲得實際讀取的字節數。

public class Utils 
{ 
public static class DownloadFileData 
{ 
    int nTotalSize; 
    int nDownloadedSize; 
} 
public interface ProgressCallback 
{ 
    void onProgress(long nCurrent, long nMax); 
} 
public static boolean downloadFile(String sFileURL, File whereToSave, DownloadFileData fileData, ProgressCallback progressCallback) 
{ 
    InputStream inputStream = null; 
    FileOutputStream fileOutput = null; 
    try 
    { 
     URL url = new URL(sFileURL); 
     URLConnection connection = url.openConnection(); 

    //set up some things on the connection 
     connection.setDoOutput(true); 
     connection.connect(); 

     fileOutput = new FileOutputStream(whereToSave); 
     inputStream = connection.getInputStream(); 
     fileData.nTotalSize = connection.getContentLength(); 
     fileData.nDownloadedSize = 0; 

      byte[] buffer = new byte[1024]; 
      int bufferLength = 0; //used to store a temporary size of the buffer 

     // now, read through the input buffer and write the contents to the file 
     while ((bufferLength = inputStream.read(buffer)) > 0) 
     { 
      // if interrupted, don't download the file further and return 
      // also restore the interrupted flag so that the caller stopped also 
      if (Thread.interrupted()) 
      { 
       Thread.currentThread().interrupt(); 
       return false; 
      } 

      // add the data in the buffer to the file in the file output stream 
      fileOutput.write(buffer, 0, bufferLength); 
      // add up the size so we know how much is downloaded 
      fileData.nDownloadedSize += bufferLength; 

      if (null != progressCallback && fileData.nTotalSize > 0) 
      { 
       progressCallback.onProgress(fileData.nDownloadedSize, fileData.nTotalSize); 
      } 
     } 
    return true; 
    } 
    catch (FileNotFoundException e) 
    { 
     return false; // swallow a 404 
    } 
    catch (IOException e) 
    { 
     return false; // swallow a 404 
    } 
    catch (Throwable e) 
    { 
     return false; 
    } 
    finally 
    { 
     // in any case close input and output streams 
     if (null != inputStream) 
     { 
      try 
      { 
       inputStream.close(); 
       inputStream = null; 
      } 
      catch (Exception e) 
      { 
      } 
     } 
     if (null != fileOutput) 
     { 
      try 
      { 
       fileOutput.close(); 
       fileOutput = null; 
      } 
      catch (Exception e) 
      { 
      } 
     } 
    } 
} 

這是處理下載的代碼片段。由於有時讀取字節的數量不正確(它是> 0,真實文件的大小爲0字節),我用outputFile.length()檢查下載文件的大小。但是即使文件真的是0字節,這也會給出> 0的值。我試圖創建一個新文件並使用recheckSizeFile.length()來讀取它的大小。仍然大小確定爲> 0,而它確實是0字節。

Utils.DownloadFileData fileData = new Utils.DownloadFileData(); 
boolean bDownloadedSuccessully = Utils.downloadFile(app.sCurrenltyDownloadedFile, outputFile, fileData, new Utils.ProgressCallback() 
        { 
... // progress bar is updated here 
}); 

if (bDownloadedSuccessully) 
{ 
    boolean bIsGarbage = false; 
    File recheckSizeFile = new File(sFullPath); 
    long nDownloadedFileSize = Math.min(recheckSizeFile.length(), Math.min(outputFile.length(), fileData.nDownloadedSize)); 
     // if the file is 0bytes, it's garbage 
    if (0 == nDownloadedFileSize) 
    { 
     bIsGarbage = true; 
    } 
    // if this is a video and if of suspiciously small size, it's 
    // garbage, too 
    else if (Utils.isStringEndingWith(app.sCurrenltyDownloadedFile, App.VIDEO_FILE_EXTENSIONS) && nDownloadedFileSize < Constants.MIN_NON_GARBAGE_VIDEO_FILE_SIZE) 
    { 
     bIsGarbage = true; 
    } 
    if (bIsGarbage) 
    { 
     ++app.nFilesGarbage; 
     app.updateLastMessageInDownloadLog("File is fake, deleting: " + app.sCurrenltyDownloadedFile); 
     // delete the garbage file 
     if (null != outputFile) 
     { 
      if (!outputFile.delete()) 
      { 
       Log.e("MyService", "Failed to delete garbage file " + app.sCurrenltyDownloadedFile); 
      } 
     } 
    } 
    else 
    { 
     ... // process the normally downloaded file 
    } 

我不確定,但我認爲在Android中有一個讀取文件大小的錯誤。有沒有人看過類似的問題?或者我可能在這裏做錯了什麼? 謝謝!

編輯:我如何確定文件是0字節: 所有下載的文件都通過上述例程。當我後來使用文件瀏覽器(Ghost Commander)查看下載文件夾時,某些文件(如10%)爲0字節。它們不能由視頻播放器播放(顯示爲「破損文件」圖標)。

+1

文件真的可以是0字節嗎?難道它不會總是有一些元數據等,爲自己存在?也許你需要更多的東西像實際的內容大小? –

+0

其實我也檢查小視頻文件刪除它們。 MIN_NON_GARBAGE_VIDEO_FILE_SIZE設置爲100kb。所以,如果一個視頻文件會有一些小的元數據塊,它肯定會在100kb以下。而且我仍然得到0字節的視頻文件不被刪除。單獨的元數據可以超過100kb嗎? – iseeall

回答

1

它在我看來像你的問題是你只檢查「垃圾」文件,如果Utils.downloadFile調用返回true。如果在getInputStream調用或第一個read下載失敗,您將創建一個零長度的文件,永遠不會被刪除。

+0

確實。我的一個愚蠢的錯誤。這是一個很好的例子,當不使用Clean Code編碼原則時會發生什麼。這些方法很長,加上文件是在一種方法中創建並傳遞給另一個,所以我只是沒有注意到所有的可能性。 – iseeall

1

您應該在FileOutputStream上調用flush()以確保將所有數據寫入文件。這應該會讓你的問題更少出現在0字節的文件中。

使用File.length()檢查0字節文件應該正常工作。你可以在設備上打開一個shell(adb shell)並運行ls -l來查看它顯示的字節數爲0(也許你的文件管理器有一些奇怪的問題)。還請調試(或放置一些日誌語句)sFullPath包含正確的文件路徑。我看不到在上面的代碼中設置sFullPath的位置,以及爲什麼不使用outputFile,而是重新創建另一個File對象。

+0

謝謝!是的,我會添加flush(),但afaik close總是在關閉前調用flush(可能是錯誤的)。 sFullPath是寫入文件的完整路徑。它將在外部存儲器(SD卡)上。我創建另一個文件只是爲了三倍檢查大小。我的意思是,我已經獲得了outputFile.length()的大小,但是我的猜測是關閉文件可能會延遲一些(?),這就是爲什麼如果我試圖在操作系統使用的任何緩衝區的內容之後立即檢查大小沒有寫入磁盤。但是,是的,大小總是> 100kb,新開放的大小也是> 0.瘋狂的東西 – iseeall