2014-01-22 28 views
1

如果我們創建一個HttpWebRequest並從響應中獲取ResponseStream,那麼數據是否會立即被完全下載,或者當我們調用流的ReadBytes時,那麼只有數據會從網絡下載,然後讀取內容?我想參考GetResponseStream()或ReadBytes()誰負責下載數據以及如何操作?

代碼樣品提到如下:

var webRequest = HttpWebRequest.Create('url of a big file approx 700MB') as HttpWebRequest; 
var webResponse = webRequest.GetResponse(); 
using (BinaryReader ns = new BinaryReader(webResponse.GetResponseStream())) 
{ 
    Thread.Sleep(60000); //Sleep for 60seconds, hope 700MB file get downloaded in 60 seconds 
    //At this point whether the response is totally downloaded or will not get downloaded at all 
    var buffer = ns.ReadBytes(bufferToRead); 
    //Or, in the above statement ReadBytes function is responsible for downloading the content from the internet. 
} 
+0

爲什麼你需要等待1分鐘?即使它工作,那麼將整個700MB文件下載到內存也是如此糟糕。 只需從流中讀取一些緩衝區,然後在本地寫入,然後再次讀取並重新寫入,就容易多了。直到文件將被完全下載。 –

+0

嗯,我只是做了一個thread.sleep,以便更容易理解web響應。getresponsestream有足夠的時間來讀取文件的所有必需內容。我想知道它是否會一次下載整個內容,或者ReadBytes是否是負責下載數據的主要功能。 –

回答

4

GetResponseStream打開並返回一個Stream對象。流對象來源於底層的Socket。此Socket是由網絡適配器異步發送的數據。數據剛剛到達並被緩衝。 GetResponseStream將阻止執行,直到第一個數據到達

ReadByte將數據從套接字層上拉到c#。 該方法將阻止執行,直到有一個字節可用

關閉流過早將結束異步傳送(關閉Socket,所述發件人將被通知的此作爲其連接將失敗),丟棄(齊平),您還沒有使用任何緩衝數據。

1

要回答關於何時開始流的問題,GetResponseStream()將開始從服務器接收數據。但是,在某些時候,如果您沒有讀取緩衝區,網絡緩衝區將變滿並且服務器將停止發送數據。有關tcp緩衝區的詳細說明,請參閱here

因此,您的60000睡眠不會幫助您,因爲沿途的網絡緩衝區將填滿,數據將停止到達,直到您讀完爲止。最好把它讀出來,然後按照大塊寫入。

有關ResponseStream here的工作原理的更多信息。 如果您想知道使用哪種緩衝區大小,請參閱here

3
var webRequest = HttpWebRequest.Create('url of a big file approx 700MB') as HttpWebRequest; 

好的,我們準備好了。如果你自己輸入或輸出一個數據流,它會有點不同,但差異是相似的。

var webResponse = webRequest.GetResponse(); 

GetResponse()回報,這將至少是已經閱讀所有的HTTP報頭。它可能已經讀取了重定向的標題,並且對它被重定向到的URI做了另一個請求。它也有可能是直接訪問緩存(直接或因爲web服務器setnt 304 Not Modified),但默認情況下,這些內容的細節對您是隱藏的。

套接字緩衝區中可能會有更多字節。

using (BinaryReader ns = new BinaryReader(webResponse.GetResponseStream())) 
{ 

在這一點上,我們有一個代表網絡流的流。

讓我們刪除Thread.Sleep()它什麼都不做,除了增加連接超時的風險。即使假設它在等待時沒有超時,由於你沒有閱讀它們,連接將從發送字節中「退出」,所以效果將比通過增加故意的減速更加緩慢。

var buffer = ns.ReadBytes(bufferToRead); 

此時,無論是bufferToRead字節已被讀出以產生byte[]或者少於bufferToRead因爲流的總尺寸均小於,在這種情況下buffer包含整個流。這需要花費很長時間。

} 

在這一點上,因爲進行了成功的HTTP GET,底層網絡接入層可能緩存響應(可能不是,如果是非常大的 - 默認的假設是非常大的請求不重複了很多,並沒有從緩存中受益)。

錯誤條件會在發生異常時引發異常,並且在這種情況下不會執行緩存(沒有緩存錯誤響應的點)。

沒有必要睡覺或以其他方式「等待」它。

這是值得考慮以下的變體,在只是一個稍低的水平通過操縱流,而不是直接通過閱讀器的工作原理:

using(var stm = webResponse.GetResponseStream()) 
{ 

我們將直接流工作;

byte[] buffer = new byte[4096]; 
do 
{ 
    int read = stm.Read(buffer, 0, 4096); 

這將返回高達 4096字節。它可能讀取較少,因爲它有一大堆字節已經可用,並且它立即返回。它只會返回0字節,如果它在流的末尾,所以這給了我們在等待和不等待之間的平衡 - 它承諾等待足夠長的時間以獲得至少一個字節,但是是否等到它得到所有4096個字節都取決於流,以選擇等待較長還是返回較少字節的效率更高;

DoSomething(buffer, 0, read); 

我們使用我們得到的字節。

} while(read != 0); 

Read()只給我們零字節,如果是在流的末尾。

} 

而且,當處理流時,響應可能被緩存,也可能不被緩存。

正如您所看到的,即使在.NET使用HttpWebResponse時我們可以訪問的最低級別,也不需要添加代碼以等待任何事情,因爲這一直是我們所做的。

您可以使用對流的異步訪問來避免等待,但是異步機制仍然意味着在可用時獲得結果。