http://blog.sina.com.cn/s/blog_6a48b80c0100sulv.html
理论上,读是把一堆本无意义的信息载体(如一串文字)转换成有意义的概念(信息)的过程;写是把一个有含义的概念用本无意义的信息载体记录起来的过程。对应起流的概念:流是一种数码信息的载体,它是没有数据结构的一长串01序列;程序里用的数据是有良好数据结构的,相当于有含义的概念。
xxxStream.Read()是流的读操作,把本无意义的流读成程序里使用的有意义的数据;xxxStream.Write()是流的写操作,把程序里的数据结构写到流中。
流的读写与观念上文件的读写不同。你编的软件的职责并不包括直接操作文件,它只需要负责把特定的数据结构写到流中即可,从流保存到文件的过程是后台调用文件系统完成的。
大块数据在通信时都是转换成流的形式的。一个流总会有一个来源,比如从文件,网络,管道。流最终也会有一个去向,比如存成文件,发送到网络(用“发送出去”说明这个过程更抽象,因为就算是以文件的形式保存,也是发送到文件系统,让文件系统自己去处理)。所以一个流概念上对应一个你想操作的文件的实体(以文件流为例),因为你编程的时候不用思考文件系统里的具体操作。
File类和Directory类相当软件虚拟了一个文件系统,而FileInfo类(xxxInfo类)相当于虚拟了一个(文件)实体。(其实一个文件实体我们只需要知道它的路径和文件名就足够了,这就是为什么FileInfo类的构造方法只需要一个全文件名)
在程序中,一个文件所能提供的只有:文件名,路径名和一串流。所有对文件的操作都归为对这三者的操作。一个FileInfo可以解决文件与路径名,一个由路径构建的FileStream实例可以解决流。
流的读操作总需要把数据源以一串01序列的形式从数据源(以磁盘为例)读到内存中的;写操作总会把内存中的一长串01序列写回数据源,如果每一次读写只针对很少的数据而读写的次数又过于频繁,内存与磁盘间的往返就会造成性能上的问题。BufferedStream是给一般的Stream在内存里加了一个缓存,这样对数据源的读取就可以先批量读到内存再访问,写操作也可以先批量放在内存再一并写到数据源。
文件有两大类:文本文件和二进制文件。文本文件存储的是文本信息(一串文字符号),而文字符号本身是和编码没有关系的,存储系统在试图把文字符号保存起来的时候才涉及编码。一个文本文件一方面在物质上是一个01序列的实体,另一方面在精神上是一串文字符号。具体说来,一个文本文件在存储的时候先指定一种编码方式,再把文件编码,最后把编码方式和码块一并存储起来,所以,它借助公认编码对外体现的就是那一串文字符号。有些时候软件出现乱码问题,要么是软件不认识那个指定的编码方式,要么是强制以不一致的编码方式解码导致。
FileStream的实例可以通过File或者FileInfo的Open方法得到,也可以通过构造函数传入一个全文件名得到,可见它其实代表这个文件的数据实体。相比之下,FileInfo代表这个文件的操作实体。
一个流自身的读写方法Read()和Write()进行的是物理的读写,即读写的是流对应实体的字节数据块。如果想对一个流代表的含义和内容进行读写,就要用XXXReader类和XXXWriter类了。
以下简要地归纳了System.IO的主要类:
Stream:
支持读取和写入字节的抽象类。不管它具体是什么形式,本质上总是可以视为一串字节序列。
File, FileInfo, Directory, DirectoryInfo:
提供抽象的FileSystemInfo类的具体实现,虚拟了文件系统。
FileStream,MemoryStream,NetworkStream:
流的具体类。其中MemoryStream是一个非缓存的数据流,它封闭的数据在内存中可以直接访问,作为一临时缓存,它很有用。
BufferedStream:
给像NetworkStream这样的数据流添加了缓存的数据流。
TextReader, TextWriter, StringReader, StringWriter,StreamReader,StreamWriter:
向数据流中读出或写入编码后的文本。其中StringReader和StringWriter把一段String视为流的源。
BinaryReader,BinaryWriter:
向数据流中读取和写入编码后的字符串或各种原始数据类型。