比較有效的使用C#讀取文件的代碼
更新時(shí)間:2007年08月12日 16:04:41 作者:
你平時(shí)是怎么讀取文件的?使用流讀取。是的沒錯(cuò),C#給我們提供了非常強(qiáng)大的類庫(又一次吹捧了.NET一番),里面封裝了幾乎所有我們可以想到的和我們沒有想到的類,流是讀取文件的一般手段,那么你真的會(huì)用它讀取文件中的數(shù)據(jù)了么?真的能讀完全么?
通常我們讀取一個(gè)文件使用如下的步驟:
1、聲明并使用File的OpenRead實(shí)例化一個(gè)文件流對象,就像下面這樣
FileStream fs = File.OpenRead(filename);
或者
FileStream fs = FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2、準(zhǔn)備一個(gè)存放文件內(nèi)容的字節(jié)數(shù)組,fs.Length將得到文件的實(shí)際大小,就像下面這樣
byte[] data = new byte[fs.Length];
3、哇!開始讀了,調(diào)用一個(gè)文件流的一個(gè)方法讀取數(shù)據(jù)到data數(shù)組中
fs.Read (data, 0, data.Length);
呵呵!我們只寫了3句就可以把文件里面的內(nèi)容原封不動(dòng)的讀出來,真是太簡潔了!可以這段代碼真的能像你預(yù)期的那樣工作么?答案是:幾乎可以!在大部分情況下上面的代碼工作的很好,但是我們應(yīng)該注意Read方法是有返回值的,既然有返回值那么一定有其道理,如果按照上面的寫法完全可以是一個(gè)沒有返回值的函數(shù)。我想返回值的目的是,為了給我們一個(gè)機(jī)會(huì)判斷實(shí)際讀取文件的大小,從而來判斷文件是否已經(jīng)完全讀完。所以上面的代碼不能保證我們一定讀完了文件里面的所有字節(jié)(雖然在很多情況下是讀完了)。下面的方法提供了一個(gè)比上面方法更安全的方法,來保證文件被完全讀出
public static void SafeRead (Stream stream, byte[] data){
int offset=0;
int remaining = data.Length;
// 只要有剩余的字節(jié)就不停的讀
while (remaining > 0){
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException("文件讀取到"+read.ToString()+"失??!");
// 減少剩余的字節(jié)數(shù)
remaining -= read;
// 增加偏移量
offset += read;
}
}
有些情況下你不知道流實(shí)際的長度比如:網(wǎng)絡(luò)流。此時(shí)可以使用類似的方法讀取流直到流里面的數(shù)據(jù)完全讀取出來為止。我們可以先初始化一段緩存,再將流讀出來的流信息寫到內(nèi)存流里面,就像下面這樣:
public static byte[] ReadFully (Stream stream){
// 初始化一個(gè)32k的緩存
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream()){ //返回結(jié)果后會(huì)自動(dòng)回收調(diào)用該對象的Dispose方法釋放內(nèi)存
// 不停的讀取
while (true){
int read = stream.Read (buffer, 0, buffer.Length);
// 直到讀取完最后的3M數(shù)據(jù)就可以返回結(jié)果了
if (read <= 0)
return ms.ToArray();
ms.Write (buffer, 0, read);
}
}
}
雖然上面的例子都比較簡單,效果也不是很明顯(大部分都是對的),也許你早就會(huì)了,沒關(guān)系這篇文章本來就是寫給初學(xué)者的。
下面的方法提供了一種使用指定緩存長度的方式讀取流,雖然在很多情況下你可以直接使用Stream.Length得到流的長度,但是不是所有的流都可以得到。
public static byte[] Read2Buffer (Stream stream, int BufferLen){
// 如果指定的無效長度的緩沖區(qū),則指定一個(gè)默認(rèn)的長度作為緩存大小
if (BufferLen < 1){
BufferLen = 0x8000;
}
// 初始化一個(gè)緩存區(qū)
byte[] buffer = new byte[BufferLen];
int read=0;
int block;
// 每次從流中讀取緩存大小的數(shù)據(jù),知道讀取完所有的流為止
while ( (block = stream.Read(buffer, read, buffer.Length-read)) > 0){
// 重新設(shè)定讀取位置
read += block;
// 檢查是否到達(dá)了緩存的邊界,檢查是否還有可以讀取的信息
if (read == buffer.Length){
// 嘗試讀取一個(gè)字節(jié)
int nextByte = stream.ReadByte();
// 讀取失敗則說明讀取完成可以返回結(jié)果
if (nextByte==-1){
return buffer;
}
// 調(diào)整數(shù)組大小準(zhǔn)備繼續(xù)讀取
byte[] newBuf = new byte[buffer.Length*2];
Array.Copy(buffer, newBuf, buffer.Length);
newBuf[read]=(byte)nextByte;
buffer = newBuf;// buffer是一個(gè)引用(指針),這里意在重新設(shè)定buffer指針指向一個(gè)更大的內(nèi)存
read++;
}
}
// 如果緩存太大則使用ret來收縮前面while讀取的buffer,然后直接返回
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}
通常我們讀取一個(gè)文件使用如下的步驟:
1、聲明并使用File的OpenRead實(shí)例化一個(gè)文件流對象,就像下面這樣
FileStream fs = File.OpenRead(filename);
或者
FileStream fs = FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2、準(zhǔn)備一個(gè)存放文件內(nèi)容的字節(jié)數(shù)組,fs.Length將得到文件的實(shí)際大小,就像下面這樣
byte[] data = new byte[fs.Length];
3、哇!開始讀了,調(diào)用一個(gè)文件流的一個(gè)方法讀取數(shù)據(jù)到data數(shù)組中
fs.Read (data, 0, data.Length);
呵呵!我們只寫了3句就可以把文件里面的內(nèi)容原封不動(dòng)的讀出來,真是太簡潔了!可以這段代碼真的能像你預(yù)期的那樣工作么?答案是:幾乎可以!在大部分情況下上面的代碼工作的很好,但是我們應(yīng)該注意Read方法是有返回值的,既然有返回值那么一定有其道理,如果按照上面的寫法完全可以是一個(gè)沒有返回值的函數(shù)。我想返回值的目的是,為了給我們一個(gè)機(jī)會(huì)判斷實(shí)際讀取文件的大小,從而來判斷文件是否已經(jīng)完全讀完。所以上面的代碼不能保證我們一定讀完了文件里面的所有字節(jié)(雖然在很多情況下是讀完了)。下面的方法提供了一個(gè)比上面方法更安全的方法,來保證文件被完全讀出
public static void SafeRead (Stream stream, byte[] data){
int offset=0;
int remaining = data.Length;
// 只要有剩余的字節(jié)就不停的讀
while (remaining > 0){
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException("文件讀取到"+read.ToString()+"失??!");
// 減少剩余的字節(jié)數(shù)
remaining -= read;
// 增加偏移量
offset += read;
}
}
有些情況下你不知道流實(shí)際的長度比如:網(wǎng)絡(luò)流。此時(shí)可以使用類似的方法讀取流直到流里面的數(shù)據(jù)完全讀取出來為止。我們可以先初始化一段緩存,再將流讀出來的流信息寫到內(nèi)存流里面,就像下面這樣:
public static byte[] ReadFully (Stream stream){
// 初始化一個(gè)32k的緩存
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream()){ //返回結(jié)果后會(huì)自動(dòng)回收調(diào)用該對象的Dispose方法釋放內(nèi)存
// 不停的讀取
while (true){
int read = stream.Read (buffer, 0, buffer.Length);
// 直到讀取完最后的3M數(shù)據(jù)就可以返回結(jié)果了
if (read <= 0)
return ms.ToArray();
ms.Write (buffer, 0, read);
}
}
}
雖然上面的例子都比較簡單,效果也不是很明顯(大部分都是對的),也許你早就會(huì)了,沒關(guān)系這篇文章本來就是寫給初學(xué)者的。
下面的方法提供了一種使用指定緩存長度的方式讀取流,雖然在很多情況下你可以直接使用Stream.Length得到流的長度,但是不是所有的流都可以得到。
public static byte[] Read2Buffer (Stream stream, int BufferLen){
// 如果指定的無效長度的緩沖區(qū),則指定一個(gè)默認(rèn)的長度作為緩存大小
if (BufferLen < 1){
BufferLen = 0x8000;
}
// 初始化一個(gè)緩存區(qū)
byte[] buffer = new byte[BufferLen];
int read=0;
int block;
// 每次從流中讀取緩存大小的數(shù)據(jù),知道讀取完所有的流為止
while ( (block = stream.Read(buffer, read, buffer.Length-read)) > 0){
// 重新設(shè)定讀取位置
read += block;
// 檢查是否到達(dá)了緩存的邊界,檢查是否還有可以讀取的信息
if (read == buffer.Length){
// 嘗試讀取一個(gè)字節(jié)
int nextByte = stream.ReadByte();
// 讀取失敗則說明讀取完成可以返回結(jié)果
if (nextByte==-1){
return buffer;
}
// 調(diào)整數(shù)組大小準(zhǔn)備繼續(xù)讀取
byte[] newBuf = new byte[buffer.Length*2];
Array.Copy(buffer, newBuf, buffer.Length);
newBuf[read]=(byte)nextByte;
buffer = newBuf;// buffer是一個(gè)引用(指針),這里意在重新設(shè)定buffer指針指向一個(gè)更大的內(nèi)存
read++;
}
}
// 如果緩存太大則使用ret來收縮前面while讀取的buffer,然后直接返回
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}
相關(guān)文章
C#?Winform消息通知之系統(tǒng)本地通知local?toast?notification
這篇文章主要為大家介紹了C#?Winform消息通知之系統(tǒng)本地通知local?toast?notification使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
C#實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出任一Word圖表的通用呈現(xiàn)方法
應(yīng)人才測評產(chǎn)品的需求,導(dǎo)出測評報(bào)告是其中一個(gè)重要的環(huán)節(jié),報(bào)告的文件類型也多種多樣,其中WORD輸出也扮演了一個(gè)重要的角色,本文給大家介紹了C#實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出任一Word圖表的通用呈現(xiàn)方法及一些體會(huì),需要的朋友可以參考下2023-10-10
Qt之調(diào)用C#的動(dòng)態(tài)庫的解決方法
這篇文章給大家介紹了Qt之調(diào)用C#的動(dòng)態(tài)庫的解決方法,環(huán)境使用的是VS2019+Qt5.12,感興趣的朋友一起看看吧2021-10-10
C#?微信支付回調(diào)驗(yàn)簽處理的實(shí)現(xiàn)
在微信支付中,當(dāng)用戶支付成功后,微信會(huì)把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,本文就詳細(xì)的介紹了C#?微信支付回調(diào)驗(yàn)簽處理,具有一定的參考價(jià)值,感興趣的可以了解一下2021-12-12
在Parallel中使用DbSet.Add()發(fā)現(xiàn)的一系列多線程問題和解決思路詳解
這篇文章主要介紹了在Parallel中使用DbSet.Add()發(fā)現(xiàn)的一系列多線程問題和解決過程的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
C#從實(shí)體對象集合中導(dǎo)出Excel的代碼
數(shù)據(jù)的導(dǎo)出是項(xiàng)目中經(jīng)常要實(shí)現(xiàn)的功能,就拿最常見的要導(dǎo)出成Excel來說,網(wǎng)上看來看去,都是介紹從Datatable中導(dǎo)出2008-08-08

