審查徵集貼:http://www.cnblogs.com/BeginnerClassroom/archive/2010/07/30/1788649.html
附錄徵集貼:http://www.cnblogs.com/BeginnerClassroom/archive/2010/08/04/1792175.html
歡迎各位園友對本書的某一部分內容進行拓展,將以附錄的形式附在書後。
要求:
- 緊緊圍繞一兩個中心展開;
- 邏輯清晰,行文流暢;
- 考慮到初學者的基礎。
- 寫作時間最好不要少於一星期。
我寫東西都是寫好以後先放在那裡,過段時間再讀,重新修改,如此反覆幾次,就基本上很流暢了。
(PS:會署名,但無稿費,因為本來就沒多少,不夠分的。當然如果發了大財,我會分給大家的。)
標題 |
作者 |
狀態 |
關於RichTextBox修改字型大小的研究 |
李雨來 |
已完稿 |
委託和介面的區別 |
湯非凡 |
正在寫 |
XML格式注釋 |
Capricornus |
正在寫 |
介面的顯式實現以及與抽象類別的比較 |
顧磊 |
正在寫 |
.NET版本變更表 |
張智鳴 |
正在寫 |
字元編碼 |
趙士敬 |
正在寫 |
讀取流時應注意的一個問題 |
黃志斌 |
正在寫 |
Regex在EmEditor裡的應用 |
柳永法 |
正在寫 |
繪圖緩衝 |
|
待選 |
非同步讀寫操作 |
|
待選 |
控制項開發、自訂控制項 |
MingHao_Hu |
正在寫 |
|
|
|
|
|
|
讀取流時應注意的一個問題
(本文由黃志斌提供)
Stream 類是所有流的抽象基類,通過它及它的子類,使程式員不必瞭解作業系統和基礎裝置的具體細節,即可對流進行“讀取”、“寫入”、“查詢”等操作。希望本文的例子能協助你掌握流的用法。
下面來研究一下Stream 類及其衍生類別的讀取資料的成員。
Stream.Read()
Stream.ReadBytes()
BinaryReader.Read()
BinaryReader.ReadBytes()
TextReader.Read()
TextReader.ReadBlock ()
Stream.Read方法用於從流中讀取位元組序列,並將流的當前位置提升相應的位元組數。在 MSDN 中有這樣一句話:“即使尚未到達流的末尾,該方法擷取到的位元組數仍可以能少於所請求的位元組數。”現在我們寫一個程式來驗證這一點。
using System;using System.IO;using Skyiv.Util;namespace Skyiv.Ben.StreamTest{ sealed class Program { static void Display(string msg, int n) { Console.WriteLine("{0,22}: {1,7:N0}", msg, n); } static void Main() { var bs = new byte[128 * 1024]; //131,072
var ftp = new FtpClient("ftp://ftp.hp.com", "anonymous", "ben@skyiv.com"); Stream stream = ftp.GetDownloadStream("pub/softpaq/allfiles.txt"); BinaryReader binaryReader = new BinaryReader(stream); TextReader textReader = new StreamReader(stream); int count1 = stream.Read(bs, 0, bs.Length); int count2 = stream.ReadBytes(bs.Length).Length; int count3 = binaryReader.Read(bs, 0, bs.Length); int count4 = binaryReader.ReadBytes(bs.Length).Length; int count5 = textReader.Read(buf, 0, buf.Length); int count6 = textReader.ReadBlock(buf, 0, buf.Length); Display("Expect", bs.Length); Display("Stream.Read", count1); Display("Stream.ReadBytes", count2); Display("BinaryReader.Read", count3); Display("BinaryReader.ReadBytes", count4); Display("TextReader.Read", count5); Display("TextReader.ReadBlock", count6); } }}
======
將這個程式運行三次的結果如下: Expect: 131,072 Stream.Read: 4,356 Stream.ReadBytes: 131,072 BinaryReader.Read: 2,904BinaryReader.ReadBytes: 131,072 TextReader.Read: 123,812 TextReader.ReadBlock: 131,072 Expect: 131,072 Stream.Read: 4,356 Stream.ReadBytes: 131,072 BinaryReader.Read: 4,356BinaryReader.ReadBytes: 131,072 TextReader.Read: 2,904 TextReader.ReadBlock: 131,072 Expect: 131,072 Stream.Read: 4,356 Stream.ReadBytes: 131,072 BinaryReader.Read: 2,904BinaryReader.ReadBytes: 131,072 TextReader.Read: 5,808 TextReader.ReadBlock: 131,072
可見,Stream.Read()、BinaryReader.Read()和TextReader.Read()方法,在尚未到達流的末尾情況下,擷取到的位元組數仍可以能少於所請求的位元組數,這種問題在處理網路流(如FTP)、裝置流(如串口輸入)等情況時經常發生,而Stream.ReadBytes()、BinaryReader.ReadBytes()、和TextReader.ReadBlock()方法則無此問題。
現在,我們通過 Reflector 來查看BinaryReader.Read()方法的來源程式代碼。
public virtual int Read(byte[] buffer, int index, int count){ if (buffer == null) { throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer")); } if (index < 0) { throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (count < 0) { throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if ((buffer.Length - index) < count) {throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); } if (this.m_stream == null) { __Error.FileNotOpen(); } return this.m_stream.Read(buffer, index, count);}
======
最後一行的m_stream的類型為 Stream,可見,BinaryReader.Read()方法在做一些必要的檢查後就是簡單地調用Stream.Read()方法,所以它們具有相同的問題。
而 BinaryReader.ReadBytes方法的來源程式代碼如下:
public virtual byte[] ReadBytes(int count){ if (count < 0) { throw new ArgumentOutOfRangeException("count", Environment. GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } if (this.m_stream == null) { __Error.FileNotOpen(); } byte[] buffer = new byte[count]; int offset = 0; do { int num2 = this.m_stream.Read(buffer, offset, count); if (num2 == 0) { break; } offset += num2; count -= num2; } while (count > 0); if (offset != buffer.Length) { byte[] dst = new byte[offset]; Buffer.InternalBlockCopy(buffer, 0, dst, 0, offset); buffer = dst; } return buffer;}
======
從上述代碼中可以看出,BinaryReader.ReadBytes 方法迴圈地調用 Stream.Read 方法,直到達到流的末尾,或者已經讀取了請求的 個位元組為止。也就是說,如果沒有到達流的末尾,該方法就一定會返回所請求的位元組。
Stream.ReadBytes()方法其實是我寫的一個擴充方法,來源程式代碼如下:
using System;using System.IO;namespace Skyiv.Util{ static class ExtensionMethods { public static byte[] ReadBytes(this Stream stream, int count) { if(count < 0) throw new ArgumentOutOfRangeException("count","??????????"); var bs = new byte[count]; var offset = 0; for (int n = -1; n != 0 && count > 0; count -= n, offset += n) n = stream.Read(bs, offset, count); if (offset != bs.Length) Array.Resize(ref bs, offset); return bs; } }}
======
測試程式中使用的 FtpClient 類是我編寫的類,可以參見我的另一篇隨筆“如何直接處理FTP伺服器上的壓縮檔”[①],其來源程式代碼如下:
using System;using System.IO;using System.Net;namespace Skyiv.Util{ sealed class FtpClient { Uri uri; string userName; string password; public FtpClient(string uri, string userName, string password) { this.uri = new Uri(uri); this.userName = userName; this.password = password; } public Stream GetDownloadStream(string sourceFile) { Uri downloadUri = new Uri(uri, sourceFile); if (downloadUri.Scheme != Uri.UriSchemeFtp) throw new ArgumentException("URI is not an FTP site"); FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(downloadUri); ftpRequest.Credentials = new NetworkCredential(userName, password); ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile; return ((FtpWebResponse)ftpRequest.GetResponse()).GetResponseStream(); } }}
======
[①] 地址為:http://www.cnblogs.com/skyivben/archive/2005/09/17/238920.html