posts - 5,  comments - 5,  trackbacks - 0

          IO操作基本上需要用到Stream相關(guān)的子類,因此這類問(wèn)題在CSDN問(wèn)得也是比較多。其實(shí)對(duì)于Stream來(lái)說(shuō),操作起來(lái)比較簡(jiǎn)單,只要對(duì)細(xì)節(jié)的處理稍微注意一下,相信在使用它的時(shí)候也會(huì)得心應(yīng)手。

           

          對(duì)于Stream相關(guān)的問(wèn)題,大致分如下幾類。

          問(wèn)題一,基本操作的問(wèn)題;

          問(wèn)題二,編碼的問(wèn)題;

          問(wèn)題三,尾部處理問(wèn)題;

          問(wèn)題四,Stream緩存問(wèn)題;

          問(wèn)題五,資源釋放問(wèn)題;

          最后一個(gè)問(wèn)題,說(shuō)說(shuō)如何使用Stream來(lái)更新大文件部分?jǐn)?shù)據(jù)。

           

          對(duì)于問(wèn)題一,基本操作的問(wèn)題,主要是讀寫問(wèn)題,主要是出現(xiàn)在文件數(shù)據(jù)比較大,需要循環(huán)寫或者讀的時(shí)候。此時(shí)正確讀的形式如下。

              // 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 );

              }

           

          可是大多數(shù)人第一次完成這樣操作的時(shí)候,都會(huì)在“nRealRead = fs.Read( bBuffer, 0, 1024 );”這一句犯錯(cuò)誤。認(rèn)為第二個(gè)參數(shù)的偏移量對(duì)于Stream而設(shè)的,所以認(rèn)為應(yīng)該用累加的值,也就是目前總共讀了多少的字節(jié)數(shù)。這里需要理解一下Stream的操作,當(dāng)進(jìn)行讀或者寫操作的時(shí)候,Stream的游標(biāo)會(huì)根據(jù)所讀或者所寫得字節(jié)而自動(dòng)向前跟進(jìn);其次Stream.Read或者Stream.Write這兩個(gè)方法中第二個(gè)參數(shù)是針對(duì)第一個(gè)Buffer參數(shù)而言的,而不是對(duì)于Stream的,因此不要在這個(gè)地方犯錯(cuò)誤。

           

          基本問(wèn)題還牽扯的就是文件打開的方式。有人經(jīng)常問(wèn),如何同時(shí)用兩個(gè)Stream打開同一個(gè)文件。其實(shí)默認(rèn)的Stream打開方式是獨(dú)享的,因此當(dāng)不指明文件為訪問(wèn)共享的時(shí)候,后打開文件操作就會(huì)出現(xiàn)異常,因此需要向我上面所寫的那樣。還有,如果需要指定當(dāng)前Stream的起始位置,可以通過(guò)Seek方法或者設(shè)置Position屬性來(lái)完成。

           

          對(duì)于問(wèn)題二,編碼問(wèn)題。有人使用Stream的子類,例如StreamReader之類來(lái)打開一個(gè)文本文件,發(fā)現(xiàn)讀出來(lái)的數(shù)據(jù)是亂碼,造成這個(gè)原因大多數(shù)由于文件中含有中文字符,同時(shí)打開文件的時(shí)候沒有指明編碼方式。由于英文和中文的編碼方式不同,因此在不指明編碼的時(shí)候有時(shí)會(huì)造成讀取中文錯(cuò)誤。此時(shí)只要使用StreamReader類型中含有Encoding參數(shù)的構(gòu)造函數(shù)即可,例如:

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

          這里只是采用系統(tǒng)默認(rèn)的編碼方式,但有可能不太適合你文件的編碼方式,因此需要在實(shí)際應(yīng)用去調(diào)試和變換這個(gè)參數(shù)。

           

          問(wèn)題三是,Stream尾部處理問(wèn)題。此類問(wèn)題所展現(xiàn)的現(xiàn)象如,復(fù)制文件的時(shí)候文件會(huì)增大。因此在使用Stream.ReadStream.Write的時(shí)候,要通過(guò)方法的返回值,來(lái)標(biāo)明真正讀和寫的字節(jié)數(shù),就像前面所寫的那樣。

              // Read data

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

              // Output data

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

          此時(shí)在輸出的時(shí)候用的不是“1024”,而是“nRealRead”做為字節(jié)有效標(biāo)示。

           

          對(duì)于問(wèn)題四,Stream緩存的問(wèn)題,這主要表現(xiàn)在寫的時(shí)候。為了避免頻繁操作IO而降低效率,大多數(shù)Stream采用異步寫的方式,也就是Stream對(duì)象要配備有一定的緩存,來(lái)暫時(shí)保存寫的數(shù)據(jù)。但緩存是有限的,當(dāng)緩存已滿后會(huì)造成后續(xù)寫的數(shù)據(jù)不能寫入,從而導(dǎo)致數(shù)據(jù)丟失。那么此時(shí)需要顯示的調(diào)用Stream.Flush方法,來(lái)把緩存的數(shù)據(jù)寫入到文件中并清空緩存。其實(shí)這并不是唯一方法,在一些Stream的子類中還提供了設(shè)置BufferSize的方法,或者提供了設(shè)置AutoFlush屬性來(lái)實(shí)現(xiàn)自動(dòng)寫入等等,因此這里大家可以根據(jù)不同需要而選擇不同方法來(lái)完成。

           

          對(duì)于Stream的釋放問(wèn)題,這可能不單單是使用Stream的問(wèn)題,可能是使用C#編程而造成的不良習(xí)慣。雖說(shuō)C#的資源是受托管的,但是對(duì)于Stream來(lái)說(shuō),如果不及時(shí)釋放,那么當(dāng)其他線程或者進(jìn)程使用此文件的時(shí)候就會(huì)造成無(wú)法打開的現(xiàn)象(由于Stream大多數(shù)都是以獨(dú)享方式打開),而且沒有及時(shí)關(guān)閉,所占用的Buffer無(wú)法及時(shí)釋放。對(duì)于資源釋放問(wèn)題,我為此專門寫過(guò)一篇文章,如果有興趣的話不妨看看。

          http://blog.csdn.net/Knight94/archive/2006/08/05/1023352.aspx

          因此養(yǎng)成一個(gè)好的習(xí)慣至關(guān)重要。其實(shí)釋放Stream很簡(jiǎn)單,要么顯示的調(diào)用其的CloseDispose這兩個(gè)方法,要么使用using程序塊,就像我前面所寫的那樣。

           

          最后一個(gè)就是如何使用Stream來(lái)更新大文件。比較常見的就是,當(dāng)文件比較大,但是需要修改的部分很少,因此想要通過(guò)Stream直接在某個(gè)位置進(jìn)行類似于刪除、插入或者替換等操作。

           

          對(duì)于一個(gè)文件的更新操作,大致分為三種,這里主要是考慮更新的位置和更新數(shù)據(jù)長(zhǎng)度。

          第一種對(duì)于文件尾擴(kuò)展的操作,內(nèi)容長(zhǎng)度不限;

          第二種等字節(jié)的替換操作,位置不限;

          最后一種就是位置不固定,字節(jié)數(shù)不確定。

          上面所說(shuō)的前兩種,進(jìn)行處理比較簡(jiǎn)單。對(duì)于第一種,只要設(shè)置FileMode的時(shí)候增加Append標(biāo)示即可。而對(duì)于等字節(jié)的替換,就更簡(jiǎn)單了,直接通過(guò)Stream.Seek找到指定的位置,然后調(diào)用Stream.Write即可。

          而最后一個(gè),是最麻煩的。比較簡(jiǎn)單的解決方式,創(chuàng)建一個(gè)臨時(shí)文件,然后一邊讀一邊寫,遇到需要修改的,先讀出來(lái)再修改最后再寫入。等全部寫完了,刪除舊文件,修改臨時(shí)文件的名稱為原來(lái)名字。

          比較麻煩的解決方式,就是通過(guò)Share方式,用一個(gè)讀Stream和一個(gè)寫Stream直接操縱源文件。這里需要注意的是,為了保證新寫的數(shù)據(jù)不要沖掉還沒讀出來(lái)的數(shù)據(jù),也就是說(shuō)要控制寫Stream所寫的位置不要超過(guò)要讀的位置。舉例說(shuō),目前需要讀的位置是文件的800字節(jié)處,也就是說(shuō)800字節(jié)以后還沒讀出來(lái)處理,此時(shí)寫Stream在寫完數(shù)據(jù)后,Stream的位置不能超過(guò)800字節(jié),如果寫采用的是緩存,那么超過(guò)800位置的數(shù)據(jù)不要立刻通過(guò)Flush進(jìn)行提交。總的來(lái)說(shuō),通過(guò)兩個(gè)Stream來(lái)操作同一個(gè)文件,對(duì)于這一點(diǎn)要特別注意,處理不好要造成死循環(huán)。

           

          Stream的問(wèn)題相對(duì)比較簡(jiǎn)單,大多數(shù)人操作的時(shí)候不注意細(xì)節(jié)。所以我這里只是稍加說(shuō)明,不做特別細(xì)的說(shuō)明。

          posted on 2008-06-03 17:42 曾科 閱讀(114) 評(píng)論(0)  編輯  收藏 所屬分類: ASP.NET
          <2025年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(3)

          隨筆檔案

          文章分類

          文章檔案

          相冊(cè)

          .net

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 瑞安市| 砀山县| 东台市| 田林县| 伊川县| 汤原县| 江津市| 元谋县| 安溪县| 从化市| 广南县| 洛隆县| 天柱县| 鄂尔多斯市| 潮安县| 湄潭县| 临武县| 含山县| 抚松县| 区。| 南宁市| 娄烦县| 鲜城| 昌宁县| 榆树市| 和静县| 胶州市| 承德市| 西峡县| 台中市| 黄平县| 东城区| 上蔡县| 沙坪坝区| 二连浩特市| 苗栗县| 呼和浩特市| 黄石市| 贡嘎县| 澄江县| 安多县|