C#_Stream

IO操做基本上須要用到Stream相關的子類,所以這類問題在CSDN問得也是比較多。其實對於Stream來講,操做起來比較簡單,只要對細節的處理稍微注意一下,相信在使用它的時候也會駕輕就熟。編程

對於Stream相關的問題,大體分以下幾類。緩存

問題一,基本操做的問題;異步

問題二,編碼的問題;函數

問題三,尾部處理問題;編碼

問題四,Stream緩存問題;spa

問題五,資源釋放問題;線程

最後一個問題,說說如何使用Stream來更新大文件部分數據。調試

對於問題一,基本操做的問題,主要是讀寫問題,主要是出如今文件數據比較大,須要循環寫或者讀的時候。此時正確讀的形式以下。對象

    // Open a file to read進程

    using( FileStream fs = new FileStream( yourFile,

                FileMode.Open, FileAccess.Read,

                FileShare.None ) )

    {

        int nRealRead = 0;

        byte[] bBuffer = new byte[1024];

        do

        {

            // Read data

            nRealRead = fs.Read( bBuffer, 0, 1024 );

            // Output data

            Debug.WriteLine( Encoding.Default.GetString( bBuffer, 0, nRealRead ) );

        }while( nRealRead == 1024 );

    }

但是大多數人第一次完成這樣操做的時候,都會在「nRealRead = fs.Read( bBuffer, 0, 1024 );」這一句犯錯誤。認爲第二個參數的偏移量對於Stream而設的,因此認爲應該用累加的值,也就是目前總共讀了多少的字節數。這裏須要理解一下Stream的操做,當進行讀或者寫操做的時候,Stream的遊標會根據所讀或者所寫得字節而自動向前跟進;其次Stream.Read或者Stream.Write這兩個方法中第二個參數是針對第一個Buffer參數而言的,而不是對於Stream的,所以不要在這個地方犯錯誤。

 基本問題還牽扯的就是文件打開的方式。有人常常問,如何同時用兩個Stream打開同一個文件。其實默認的Stream打開方式是獨享的,所以當不指明文件爲訪問共享的時候,後打開文件操做就會出現異常,所以須要向我上面所寫的那樣。還有,若是須要指定當前Stream的起始位置,能夠經過Seek方法或者設置Position屬性來完成。

對於問題二,編碼問題。有人使用Stream的子類,例如StreamReader之類來打開一個文本文件,發現讀出來的數據是亂碼,形成這個緣由大多數因爲文件中含有中文字符,同時打開文件的時候沒有指明編碼方式。因爲英文和中文的編碼方式不一樣,所以在不指明編碼的時候有時會形成讀取中文錯誤。此時只要使用StreamReader類型中含有Encoding參數的構造函數便可,例如:

using( StreamReader sr = new StreamReader( yourFile, Encoding.Default ) )

這裏只是採用系統默認的編碼方式,但有可能不太適合你文件的編碼方式,所以須要在實際應用去調試和變換這個參數。

 

問題三是,Stream尾部處理問題。此類問題所展示的現象如,複製文件的時候文件會增大。所以在使用Stream.ReadStream.Write的時候,要經過方法的返回值,來標明真正讀和寫的字節數,就像前面所寫的那樣。

    // Read data

    nRealRead = fs.Read( bBuffer, 0, 1024 );

    // Output data

    Debug.WriteLine( Encoding.Default.GetString( bBuffer, 0, nRealRead ) );

此時在輸出的時候用的不是「1024」,而是「nRealRead」作爲字節有效標示。

 

對於問題四,Stream緩存的問題,這主要表如今寫的時候。爲了不頻繁操做IO而下降效率,大多數Stream採用異步寫的方式,也就是Stream對象要配備有必定的緩存,來暫時保存寫的數據。但緩存是有限的,當緩存已滿後會形成後續寫的數據不能寫入,從而致使數據丟失。那麼此時須要顯示的調用Stream.Flush方法,來把緩存的數據寫入到文件中並清空緩存。其實這並非惟一方法,在一些Stream的子類中還提供了設置BufferSize的方法,或者提供了設置AutoFlush屬性來實現自動寫入等等,所以這裏你們能夠根據不一樣須要而選擇不一樣方法來完成。

 

對於Stream的釋放問題,這可能不僅僅是使用Stream的問題,多是使用C#編程而形成的不良習慣。雖然說C#的資源是受託管的,可是對於Stream來講,若是不及時釋放,那麼當其餘線程或者進程使用此文件的時候就會形成沒法打開的現象(因爲Stream大多數都是以獨享方式打開),並且沒有及時關閉,所佔用的Buffer沒法及時釋放。

所以養成一個好的習慣相當重要。其實釋放Stream很簡單,要麼顯示的調用其的CloseDispose這兩個方法,要麼使用using程序塊,就像我前面所寫的那樣。

最後一個就是如何使用Stream來更新大文件。比較常見的就是,當文件比較大,可是須要修改的部分不多,所以想要經過Stream直接在某個位置進行相似於刪除、插入或者替換等操做。

 

對於一個文件的更新操做,大體分爲三種,這裏主要是考慮更新的位置和更新數據長度。

第一種對於文件尾擴展的操做,內容長度不限;

第二種等字節的替換操做,位置不限;

最後一種就是位置不固定,字節數不肯定。

上面所說的前兩種,進行處理比較簡單。對於第一種,只要設置FileMode的時候增長Append標示便可。而對於等字節的替換,就更簡單了,直接經過Stream.Seek找到指定的位置,而後調用Stream.Write便可。

而最後一個,是最麻煩的。比較簡單的解決方式,建立一個臨時文件,而後一邊讀一邊寫,遇到須要修改的,先讀出來再修改最後再寫入。等所有寫完了,刪除舊文件,修改臨時文件的名稱爲原來名字。

比較麻煩的解決方式,就是經過Share方式,用一個讀Stream和一個寫Stream直接操縱源文件。這裏須要注意的是,爲了保證新寫的數據不要衝掉還沒讀出來的數據,也就是說要控制寫Stream所寫的位置不要超過要讀的位置。舉例說,目前須要讀的位置是文件的800字節處,也就是說800字節之後還沒讀出來處理,此時寫Stream在寫完數據後,Stream的位置不能超過800字節,若是寫採用的是緩存,那麼超過800位置的數據不要馬上經過Flush進行提交。總的來講,經過兩個Stream來操做同一個文件,對於這一點要特別注意,處理很差要形成死循環。

相關文章
相關標籤/搜索