2014-10-28 49 views
0

我見過this code sample它 - 從流中讀取到緩衝區中:C#中的流讀取變化?

byte[] buffer = new byte[1024 * 32]; 
int bytesRead; 

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
{ 
    //... 
} 

但看的stream.Read(..,0,..)第二個參數是該zero-based byte offset in buffer at which to begin storing the data read from the current stream

那麼每次的偏移量是多少?誰說它不會覆蓋這些索引的數據?

恰恰相反:我也看到了this example

int read, offset = 0; 
    while(count > 0 && (read = source.Read(buffer, offset, count)) > 0) { 
     offset += read; 
     count -= read; 
    } 

所以這裏的相互抵消閱讀(這似乎更符合邏輯的我)

但我必須失去了一些東西后抵消:

我的觀察是正確的嗎?我應該什麼時候使用每種情況?

注意,我的pov是網絡流:發送文件。

+0

我不明白。是第一個樣本覆蓋,第二個樣本增加了偏移量,不覆蓋。你的問題是什麼? – 2014-10-28 09:08:04

+0

@SriramSakthivel如果您通過網絡發送文件並不斷寫入overriting 0索引,那麼接收方已經讀取了位於流開頭的第一個字節的誰? – 2014-10-28 09:09:58

+0

通常發送的消息具有'End Of Text'字符(請參見ascii表格),告訴您消息已完成。第一個通常在內存較少時使用(因爲您已經預先定義了緩衝區的長度,您可能會從第二個例子得到'超出範圍錯誤的索引') – jbutler483 2014-10-28 09:11:58

回答

5

它們都是有用的代碼示例,只是在不同的情況下。讓我們來挑選你的第一個例子中添加一些代碼:

Socket socket = ...; 

byte[] buffer = new byte[1024 * 32]; 
int bytesRead; 

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
{ 
    socket.BeginSend(buffer, 0, bytesRead , SocketFlags.None, null, null); 
    // Wait for completion doing something else? 
} 

在這種情況下buffer重用每次然後是,數據將被覆蓋,因爲你的時間讀一大塊它的預期的行爲,你用它你繼續。

你的第二個例子是非常不同的:你正在填充一個buffer讀數據,但你沒有讀所有的數據在一起,你每讀一個較小的塊,然後offset目標buffer必須增加。

它們有何不同?在第一種情況下,緩衝區可以儘可能小(理想情況下即使是一個字節),多次讀取也會消耗輸入流。在第二種情況下,緩衝區必須足夠大以容納您需要的所有數據。

// Note we need to know file size in advance and buffer must be big enough 
// to accommodate all data we need 
int read, offset = 0; 
while(count > 0 && (read = source.Read(buffer, offset, count)) > 0) { 
    socket.BeginSend(buffer, offset , read, SocketFlags.None, null, null); 

    // Here we don't need to wait BeginSend() completes. 

    offset += read; 
    count -= read; 
} 

哪一個更好?很難說,如果你一次性分配所有內存,那麼你很少需要通過增加offset來增加offset(我唯一可以考慮的是性能優化,因爲在輸入流上的塊大小或者當你想要 - 並行 - 在讀取新數據時對接收到的數據進行一些處理)。相比之下分配足夠大到可以容納所有數據的緩衝區至少有兩大弊端:

  • 必須知道文件的大小提前(和它並非總是如此);
  • 如果文件足夠大,那麼您將運行內存不足

一般(IMO)如果第一種方法(重複使用相同的緩衝區)在大多數情況下還不錯,你可能有從單一的讀取(和非阻塞發送)性能增益是大多數網絡可以忽略不計情況和缺點是嚴重的。總結:

 
           1    2 
Unknown file size    yes    no 
Can run out of memory   yes    no 
Parallel processing friendly no    yes 
Performance optimized   no    yes 

當然,你也可以「混」兩種方法:一種大與多個較小的讀取循環緩衝區,每個讀你超前偏移指針開始一個新的並行讀取和做處理在上一個(S)。有了這個,你可以從兩種方法中獲得好處,但調整起來有點棘手(因爲併發訪問和可能重疊的讀/寫)。

+0

那麼你會用哪種方法通過networkstream發送文件?(首先?) – 2014-10-28 09:11:56

+0

首先 - 如果你有錯誤信息,那麼你不必再次發送所有的東西(就像你正在逐行處理) – jbutler483 2014-10-28 09:13:36

+0

@RoyiNamir我試着在答案中解釋,但總之:幾乎總是第一種方法可能會更好(是的,「差不多」和「可能」不被大小寫使用)。 – 2014-10-28 09:18:48

3

你已經錯過了原來的答案的重要組成部分:

byte[] buffer = new byte[1024 * 32]; 
int bytesRead; 

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
{ 
    // Use the data you've read 
} 

你使用你已經讀入緩衝區,因此它可以再被扔掉的數據(替換)。如果你有一個潛在的大流,並且不想受內存問題的影響,這很有用。

在第二個示例中,您將能夠將整個流內容讀入緩衝區並處理整個內容。

1

這兩個樣本是對的,我讀了the link code

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
{ 
    // Use the data you've read once you have received,and then thow it away. 
    //So,you can cover the old data. 
} 

while(count > 0 && (read = source.Read(buffer, offset, count)) > 0) { 
    offset += read; 
    count -= read; 
    //received all data from the stream,and then use them. 
    //So you can't cover the old data. 
} 

有兩種方法可用。