2009-12-29 63 views
2

我看到下面得到該文件到數組,這又作爲SQL命令將其插入到BLOB列一個參​​數代碼:爲什麼我需要逐個讀取文件緩衝?

using (FileStream fs = new FileStream(soubor,FileMode.Open,FileAccess.Read)) 

int length = (int)fs.Length; 
buffer = new byte[length]; 
int count; 
int sum = 0; 
while ((count = fs.Read(buffer, sum, length - sum)) > 0) 
    sum += count; 

爲什麼我不能簡單地做:

fs.Read(緩衝區,0,長度)以便將文件內容複製到緩衝區中?

感謝

回答

3

由於您的文件可能會非常大,緩衝區有4-32 KB的通常是一個固定的大小。通過這種方式,你知道你並不是一廂情願地填滿你的記憶。

當然,如果你知道你的文件的大小不是太大,或者如果你將內容存儲在內存中,沒有理由不一次全部讀取它。

雖然,如果您想直接將文件內容讀入變量,則不需要Stream API。而是使用

File.ReadAllText(...) 

File.ReadAllBytes(...) 
+0

有一個很好的理由不承擔* *您可以一次性讀取它:在'Stream' API並不能保證它會在一個呼叫讀到的一切。 – 2009-12-29 12:20:27

+0

'buffer'顯式設置爲文件的長度。所以你的第一段沒有真正回答這個問題。 – 2009-12-29 12:23:22

4

還有更給它不僅僅是「的文件可能不適合在內存」。爲Stream.Read合同明確說:

這種方法的

實現從 電流流讀取 最大的數個字節,並將它們存儲在緩衝區 開始偏移量。 流內的當前位置是 先讀取的字節數;然而,如果發生異常,流 內的當前位置保持不變。實現 返回讀取的字節數。僅當 位置當前位於 流的末尾時, 返回值爲零。在 沒有數據可用的情況下,該實現將 阻塞,直到可以讀取至少一個字節的數據 。僅當 流 中沒有更多數據且預期不再有更多數據(例如 關閉的套接字或文件結尾)時,只讀取返回0。即使未到達流的結尾 , 實現也可以自由返回比請求少的 字節。

請注意最後一句 - 您不能依靠一個電話來Stream.Read來讀取所有內容。

FileStream.Read該文檔具有類似的警告:

讀入 緩衝區的字節總數。如果 字節當前不是 可用,則可能小於 所請求的字節數,如果達到 流的末尾,則可能爲零。

對於本地文件系統,我不確定這是否真的會發生 - 但它可以爲網絡掛載的文件。你想讓你的應用變得脆弱嗎?

在一個循環看書做事可靠的方法。我個人更喜歡不要求流支持Length財產,或者:

public static byte[] ReadFully(Stream stream) 
{ 
    byte[] buffer = new byte[8192]; 
    using (MemoryStream tmpStream = new MemoryStream()) 
    { 
     int bytesRead; 
     while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) 
     { 
      tmpStream.Write(buffer, 0, bytesRead); 
     } 
     return tmpStream.ToArray(); 
    } 
} 

當長度事先知道,但它是很好的和簡單的稍微低效率的。您只需實施一次,將其放入實用程序庫中,並在需要時隨時撥打電話。如果您確實介意效率損失,則可以使用CanSeek來測試Length屬性是否受支持,並在該情況下反覆讀入單個緩衝區。請注意,儘管在閱讀時,流的長度可能會發生變化......

當然,File.ReadAllBytes會更簡單,當您只需處理文件而不是一般流。

1

一個簡單的fs.Read(buffer, 0, length)可能會工作,它甚至會很難找到一個測試來打破它。但它只是不保證,它可能會在未來打破。

這裏最好的解決辦法是使用一個專門的方法從庫。在這種情況下

byte[] buffer = System.IO.File.ReadAllBytes(fileName); 

就讓我們來看看與反射證實,這將讓你的局部緩衝邏輯你流的異常安全Dispose()

而當框架的未來版本允許更好的方法來做到這一點你的代碼會自動的利潤。