一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

淺談 Stream.Read 方法

Microsoft .NET Framework Base Class Library 中的 Stream.Read 方法:

Stream.Read 方法

當(dāng)在派生類中重寫時(shí),從當(dāng)前流讀取字節(jié)序列,并將此流中的位置提升讀取的字節(jié)數(shù)。

語法

public abstract int Read(byte[] buffer, int offset, int count)

參數(shù)

  • buffer: 字節(jié)數(shù)組。此方法返回時(shí),該緩沖區(qū)包含指定的字符數(shù)組,該數(shù)組的 offset 和 (offset + count -1) 之間的值由從當(dāng)前源中讀取的字節(jié)替換。
  • offset: buffer 中的從零開始的字節(jié)偏移量,從此處開始存儲從當(dāng)前流中讀取的數(shù)據(jù)。
  • count: 要從當(dāng)前流中最多讀取的字節(jié)數(shù)。

返回值

讀入緩沖區(qū)中的總字節(jié)數(shù)。如果當(dāng)前可用的字節(jié)數(shù)沒有請求的字節(jié)數(shù)那么多,則總字節(jié)數(shù)可能小于請求的字節(jié)數(shù),或者如果已到達(dá)流的末尾,則為零 (0)。

備注

此方法的實(shí)現(xiàn)從當(dāng)前流中讀取最多的 count 個(gè)字節(jié),并將它們存儲在從 offset 開始的 buffer 中。流中的當(dāng)前位置提升已讀取的字節(jié)數(shù);但是,如果出現(xiàn)異常,流中的當(dāng)前位置保持不變。實(shí)現(xiàn)返回已讀取的字節(jié)數(shù)。僅當(dāng)位置當(dāng)前位于流的末尾時(shí),返回值才為零。如果沒有任何可用的數(shù)據(jù),該實(shí)現(xiàn)將一直阻塞到至少有一個(gè)字節(jié)的數(shù)據(jù)可讀為止。僅當(dāng)流中不再有其他的數(shù)據(jù),而且也不再需要更多的數(shù)據(jù)(如已關(guān)閉的套接字或文件尾)時(shí),Read 才返回 0。即使尚未到達(dá)流的末尾,實(shí)現(xiàn)仍可以隨意返回少于所請求的字節(jié)。

請注意上述的 MSDN 中的最后一句話。我們寫一個(gè)程序來驗(yàn)證這一點(diǎn):

using System;using System.IO;using Skyiv.Util;namespace Skyiv.Ben.StreamTest{  sealed class Program  {    static void Main()    {      var bs = new byte[128 * 1024];      var stream = new FtpClient("ftp://ftp.hp.com", "anonymous", "ben@skyiv.com").        GetDownloadStream("pub/softpaq/allfiles.txt"); // 568,320 bytes      var br = new BinaryReader(stream);      Display("Expect", bs.Length);      Display("Stream.Read", stream.Read(bs, 0, bs.Length));      Display("BinaryReader.Read", br.Read(bs, 0, bs.Length));      Display("BinaryReader.ReadBytes", br.ReadBytes(bs.Length).Length);      Display("Stream.Readbytes", stream.ReadBytes(bs.Length).Length);    }    static void Display(string msg, int n)    {      Console.WriteLine("{0,22}: {1,7:N0}", msg, n);    }  }}

將這個(gè)程序運(yùn)行三次的結(jié)果如下:

                Expect: 131,072           Stream.Read:  50,604     BinaryReader.Read:  11,616BinaryReader.ReadBytes: 131,072      Stream.Readbytes: 131,072                Expect: 131,072           Stream.Read:   1,452     BinaryReader.Read:   2,904BinaryReader.ReadBytes: 131,072      Stream.Readbytes: 131,072                Expect: 131,072           Stream.Read:   4,356     BinaryReader.Read: 131,072BinaryReader.ReadBytes: 131,072      Stream.Readbytes: 131,072

可見,Stream.Read 方法和 BinaryReader.Read 方法在尚未到達(dá)流的末尾情況下可以返回少于所請求的字節(jié)

通過使用 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("ArgumentOutOfRan
ge_NeedNonNegNum"
)); } if (count < 0) { throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRa
nge_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 類的基礎(chǔ)流。可見,BinaryReader.Read 方法在做一些必要的檢查后就是簡單地調(diào)用 Stream.Read 方法。

BinaryReader.ReadBytes 方法的源程序代碼如下:

public virtual byte[] ReadBytes(int count){  if (count < 0)  {    throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRan
ge_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 方法循環(huán)地調(diào)用 Stream.Read 方法,直到達(dá)到流的末尾,或者已經(jīng)讀取了 count 個(gè)字節(jié)。也就是說,如果沒有到達(dá)流的末尾,該方法就一定會返回所請求的字節(jié)。

MSDN 文檔中對這兩個(gè)方法的描述:

  • BinaryReader.Read 方法:將 index 作為字節(jié)數(shù)組中的起始點(diǎn),從流中讀取 count 個(gè)字節(jié)。
  • BinaryReader.ReadBytes 方法:從當(dāng)前流中將 count 個(gè)字節(jié)讀入字節(jié)數(shù)組,并使當(dāng)前位置提升 count 個(gè)字節(jié)。
  • 上述兩個(gè)方法的備注BinaryReader 在讀取失敗后不還原文件位置。

也就是說,雖然 BinaryReader.Read 方法和 Stream.Read 方法一樣在尚未到達(dá)流的末尾情況下可以返回少于所請求的字節(jié),但是在 MSDN 文檔中并沒有指出這一點(diǎn),我們寫程序的時(shí)候要小心,避免掉入這個(gè)陷阱。

 

上述的測試程序中用到了 Stream.ReadBytes 方法,其實(shí)是一個(gè)擴(kuò)展方法,源程序代碼如下:

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", "要求非負(fù)數(shù)");      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服務(wù)器上的壓縮文件”,其源程序代碼如下:

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();    }  }}

 

我在上一篇隨筆“【算法】利用有限自動機(jī)進(jìn)行字符串匹配”中給出了一道思考題如下:

上面的第二個(gè) C# 程序中有一個(gè) bug,但是這個(gè) bug 在絕大多數(shù)情況下都不會表現(xiàn)出來。所以這個(gè)程序能夠 Accepted。

親愛的讀者,你能夠找出這個(gè) bug 嗎?

提示,這個(gè) bug 和字符串匹配算法無關(guān),并且第一個(gè) C# 程序中不存在這個(gè) bug 。

上述思考題中的第二個(gè) C# 程序的 Main 方法如下所示:

static void Main(){  var s = new byte[10000000 + 2 * 1000 + 100];  int i = 0, n = Console.OpenStandardInput().Read(s, 0, s.Length);  while (s[i++] != '/n') ;  for (int c, q = 0; i < n; q = 0)  {    while ((c = s[i++]) != '/n') if (q < 99 && c != '/r') q = delta[q, Array.IndexOf(a, c) + 1];    Console.WriteLine((q < 4) ? "YES" : "NO");  }}

這個(gè) bug 至今還沒有人找到。實(shí)際上,該方法的頭兩個(gè)語句應(yīng)改為:

var s = new BinaryReader(Console.OpenStandardInput()).ReadBytes(10000000 + 2 * 1000 + 100);int i = 0, n = s.Length;  

這是因?yàn)?Steam.Read 方法在尚未到達(dá)流的末尾情況下可以返回少于所請求的字節(jié),這有可能導(dǎo)致只讀取了部分輸入而產(chǎn)生 bug 。

NET技術(shù)淺談 Stream.Read 方法,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 草草精品视频 | 一二三区视频 | 99久久精品国产高清一区二区 | 91国内在线 | 黄视频大全 | 久久精品区 | 国产亚洲精品午夜高清影院 | www.色哟哟| 一级女毛片 | 亚洲第一视频在线播放 | 热伊人99re久久精品最新地 | 国产成人精品999在线 | 久久99精品国产麻豆 | 日韩精品久久久免费观看夜色 | 中文字幕伊人 | 欧美日韩一区妖精视频yjsp | 一级寡妇乱色毛片全场免费 | 苦瓜se在线精品视频 | 免费永久在线观看污污的网站 | 国产在线观看91 | 9丨精品国产高清自在线看 aⅴ一区二区三区 | 日韩免费视频播放 | 一区二区三区免费 | yiren综合| 亚洲另类小说网 | 97爱爱| 午夜视频在线免费观看 | 美女扒开屁股让男人桶视频网站 | 国产欧美一区二区三区在线看 | 欧美成国产精品 | 五月天婷婷精品视频 | 国产在线色视频 | 欧美成人第一页 | 99热国产在线 | 亚洲第一区视频在线观看 | 国产成人欧美 | 91精品网站 | 免费观看四虎精品国产永久 | 天天干天天综合 | 国产亚洲综合精品一区二区三区 | 51国产午夜精品免费视频 |