The stream. Read method in the Microsoft. NET Framework base class Library:
Stream. Read Method
When being rewritten in a derived class, the system reads the byte sequence from the current stream and increases the position in the stream to the number of bytes.
Syntax:
Public abstract int read (byte [] buffer, int offset, int count)
Parameters:
- Buffer: Byte array. When this method is returned, the buffer contains the specified character array.OffsetAnd (Offset+Count-1) the value is replaced by the byte read from the current source.
- Offset:BufferThe Byte offset from the beginning of 0, from which the data read from the current stream is stored.
- Count: Maximum number of bytes to read from the current stream.
Return Value:
The total number of bytes in the read buffer. If the number of available bytes is not as large as the number of requested bytes, the total number of bytes may be smaller than the number of requested bytes, or if it has reached the end of the stream, it will be zero (0 ).
Remarks:
The implementation of this method reads the most from the current streamCountAnd store them inOffsetStartBuffer. The current position in the stream increases the number of bytes read. However, if an exception occurs, the current position in the stream remains unchanged. Returns the number of read bytes. The return value is zero only when the current position is at the end of the stream. If there is no available data, this implementation will be blocked until at least one byte of data is readable. Only when no other data exists in the stream, and more data (such as the closed socket or the end of the file) is no longer needed,ReadReturns 0.Even if the stream has not reached the end, the implementation can still return less than the requested byte at will.
Pay attention to the last sentence in the above msdn. Let's write a program to verify this:
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); } }}
The result of running the program three times is as follows:
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
It can be seen that the stream. Read method and binaryreader. Read MethodIf the Stream does not reach the end, the returned byte is less than the requested byte..
Use reflector to view the source code of the binaryreader. Read method, as shown below:
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);}
In the last line of the above Code, the m_stream type is stream, which is the basic stream of the binaryreader class. It can be seen that the binaryreader. Read method simply calls the stream. Read method after some necessary checks.
The source code of binaryreader. readbytes is as follows:
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;}
From the code above, we can see that the binaryreader. readbytes method cyclically calls the stream. Read method until it reaches the end of the stream or has readCountBytes. That is to say, if the Stream does not reach the end, this method will certainly return the requested byte.
Description of the two methods in the msdn document:
- Binaryreader. ReadMethod: Use index as the starting point of the byte array and read count bytes from the stream.
- Binaryreader. readbytesMethod: Reads count bytes from the current stream into the byte array and increases the current position by Count bytes.
- Remarks of the above two methods: Binaryreader does not restore the file location after reading fails.
That is to say, although the binaryreader. Read method is the same as the stream. Read methodIf the Stream does not reach the end, the returned byte is less than the requested byte.But this is not pointed out in the msdn document. We should be careful when writing programs to avoid falling into this trap.
The stream. readbytes method is used in the above test. It is actually an extension method. The source code is as follows:
Using system; using system. io; namespace skyiv. util {static class extensionmethods {public static byte [] readbytes (this stream, int count) {If (count <0) throw new argumentoutofrangeexception ("count ", "non-negative"); 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 ;}}}
The above test program also uses the ftpclient class. For more information, see "How to directly process compressed files on the FTP server" in another article. The source code is as follows:
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(); } }}
In the previous article "[algorithm] Using Finite automatic machine for string matching", I gave the following questions:
There is a bug in the second C # program above, but this bug is not displayed in most cases. So this program can be accepted.
Dear reader, can you find out this bug?
Note: This bug is irrelevant to the string matching algorithm and does not exist in the first C # program.
The main method of the second C # program in the above questions is as follows:
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"); }}
No one has found this bug. In fact, the first two statements of this method should be changed:
var s = new BinaryReader(Console.OpenStandardInput()).ReadBytes(10000000 + 2 * 1000 + 100);int i = 0, n = s.Length;
This is because the stream. Read MethodIf the Stream does not reach the end, the returned byte is less than the requested byte.This may cause a bug that only some input is read.