2013-04-29 78 views
3

我正在單獨從網上下載文件。像3個地區一樣。可以說我必須下載一個大小爲1024kB的文件,並且我已經將該區域設置爲0-340kB,341-680kB和681kB-1024kB。我有單獨的每個部分的線程。但是,我現在的問題是,將下載的文件內容寫入單個文件。寫下載文件的部分區域

由於我們有3個線程,每個線程都會按順序下載需要寫入文件的部分。

我該如何做到這一點?我想到有3個臨時文件並寫入它們。一旦所有文件寫入,我必須逐個文件讀取並寫入一個文件。我覺得這是一種開銷。還有其他更好的方法嗎?

在此先感謝。

+0

我不確定這個,所以我把它作爲評論發佈,但是你不能在文件中的指定位置寫入嗎?既然你知道每個部分的大小,我認爲你可以創建一個1024kB的空白文件,並且每個線程都可以從一個不同的索引開始寫。 – DeadlyJesus 2013-04-29 12:44:36

+0

爲什麼有人希望有三個線程來下載文件並大幅增加開銷? – 2013-04-29 12:50:12

+0

實際上,我想通過將文件分割成多個部分並分別下載它們來提高文件下載速度,從而提高整體速度。這是我想要實現的邏輯背後的想法 – Dinesh 2013-04-29 14:18:13

回答

0

要清楚,我不相信這種方法實際上會提高下載速度。不過,如果您從多個鏡像下載相同的文件,它可能會提供更一致的下載速度。

首先,如果您的文件不是太大,您可以在寫出之前緩衝所有文件。因此,分配你的所有線程可以訪問一個緩衝區:

byte[] buf = new byte[fileSize]; 

現在你創建一個合適的主題類型:

public class WriterThread extends Thread 
{ 
    byte[] buf; 
    int write_pos, write_remaining; 

    public WriterThread(byte[] buf, int start, int len) 
    { 
     this.buf = buf; 
     this.write_pos = start; 
     this.write_remaining = len; 
    } 

    @Override 
    public void run() 
    { 
     try (Socket s = yourMethodForSettingUpTheSocketConnection(); 
      InputStream istream = s.getInputStream()) { 
      while (this.write_remaining > 0) { 
       int read = istream.read(this.buf, this.write_pos, this.write_remaining); 
       if (read == -1) error("Not enough data received"); 
       this.write_remaining -= read; 
       this.write_pos += read; 
      } 
      // otherwise you are done reading your chunk! 
     } 
    } 
} 

現在你可以開始爲許多WriterThread對象與適當的開始和長度。例如,對於一個文件,是6000個字節大小:

byte[] buf = new byte[6000]; 
WriterThread t0 = new WriterThread(buf, 0, 3000); 
WriterThread t1 = new WriterThread(buf, 3000, 3000); 
t0.start(); 
t1.start(); 
t0.join(); 
t1.join(); 
// check for errors 

注意的重要一點在這裏:每個WriterThreads都有referecence完全相同的緩衝,只是不同的偏移,它開始於寫作。當然,你必須確保yourMethodForSettingUpTheSocketConnection請求從偏移量this.write_pos開始的數據;你如何做到這一點取決於你使用的網絡協議,超出了你所問的範圍。

如果您的文件太大而無法放入內存,則此方法無效。相反,您必須先使用(較慢)方法首先創建一個大文件,然後寫入該文件。雖然我還沒有嘗試過,你應該能夠使用java.nio.file.File.newByteChannel()' to set up a suitable SeekableByteChannel as your output file. If you create such a SeekableByteChannel sbc`,那麼你應該能夠做到

sbc.location(fileSize - 1); // move to the specified position in the file 
sbc.write(java.nio.ByteBuffer.allocate(1)); // grow the file to the expected final size 

然後用每個線程一個不同SeekableByteChannel對象,指向同一個文件在磁盤上,並使用SeekableByteChannel.location(int)方法設置寫入起始位置。你需要一個臨時byte[]圍繞你可以用一個ByteBuffer(通過ByteBuffer.wrap()),但在其他方面的戰略是類似於上面:

thread_local_sbc.location(this.write_pos); 

,然後每thread_local_sbc.write()將會寫入文件開始this.write_pos