审查征集贴: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版本变更表 | 张智鸣 | 正在写 |
| 字符编码 | 赵士敬 | 正在写 |
| 读取流时应注意的一个问题 | 黄志斌 | 正在写 |
| 正则表达式在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,904 BinaryReader.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,356 BinaryReader.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,904 BinaryReader.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
浙公网安备 33010602011771号