比如压缩流、加密流,这些流不仅有Stream的所有特征,还有自己的个性。它们不仅继承Stream类,还引用Stream类。这些通过"装饰器模式"来实现的流包括:BufferedStream, DeflateStream, GZipStream, CryptoStream, AuthenticateStream.
BufferedStream类是一个流的包装类,对流进行”缓存功能的扩展包装”,它是一个装饰器类
为什么MemoryStream 同样也是在内存中对流进行操作,和BufferedStream有什么区别呢?BufferedStream并不是将所有内容都存放到内存中,而MemoryStream则是。BufferedStream必须跟其他流如FileStream结合使用,而MemoryStream则不用
class Program { static void Main(string[] args) { Server server = new Server("http://www.163.com/"); server.FetchWebPageData(); } } public class Server { //端口 const int webPort = 80; //默认接收缓存大小 byte[] receiveBufferBytes = new byte[4096]; //需要获取网页的url private string webPageURL; public Server(string webPageUrl) { webPageURL = webPageUrl; } /// <summary> /// 从该网页上获取数据 /// </summary> public void FetchWebPageData() { if (!string.IsNullOrEmpty(webPageURL)) FetchWebPageData(webPageURL); Console.ReadLine(); } /// <summary> /// 从该网页上获取数据 /// </summary> /// <param name="webPageURL">网页url</param> private void FetchWebPageData(string webPageURL) { //通过url获取主机信息 IPHostEntry iphe = Dns.GetHostEntry(GetHostNameBystrUrl(webPageURL)); Console.WriteLine("远程服务器名: {0}", iphe.HostName); //通过主机信息获取其IP IPAddress[] address = iphe.AddressList; IPEndPoint ipep = new IPEndPoint(address[0], 80); //实例化一个socket用于接收网页数据 Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //连接 socket.Connect(ipep); if (socket.Connected) { //发送头文件,这样才能下载网页数据 socket.Send( Encoding.ASCII.GetBytes( this.GetHeader(webPageURL))); } else { return; } //接收头一批数据 var count = socket.Receive(receiveBufferBytes); //转化成string var getString = Encoding.Default.GetString(receiveBufferBytes); //创建文件流 FileStream fs = new FileStream(@"d:\\Test.html", FileMode.OpenOrCreate); //创建缓存流 BufferedStream bs = new BufferedStream(fs); using (fs) { using (bs) { byte[] finalContent = Encoding.Default.GetBytes(getString.ToCharArray()); //将头一批数据写入本地硬盘 bs.Write(finalContent, 0, finalContent.Length); //循环通过socket接收数据 while (count > 0) { count = socket.Receive(receiveBufferBytes, receiveBufferBytes.Length, SocketFlags.None); //直接将获取到的byte数据写入本地硬盘 bs.Write(receiveBufferBytes, 0, receiveBufferBytes.Length); Console.WriteLine(Encoding.Default.GetString(receiveBufferBytes)); } bs.Flush(); fs.Flush(); bs.Close(); fs.Close(); } } } /// <summary> /// 得到header /// </summary> /// <param name="url">网页url</param> /// <returns>header字符串</returns> private string GetHeader(string webPageurl) { return "GET " + GetRelativeUrlBystrUrl(webPageurl) + " HTTP/1.1\r\nHost: " + GetHostNameBystrUrl(webPageurl) + "\r\nConnection: Close\r\n\r\n"; } /// <summary> /// 得到相对路径 /// </summary> /// <param name="strUrl">网页url</param> /// <returns></returns> private string GetRelativeUrlBystrUrl(string strUrl) { int iIndex = strUrl.IndexOf(@"//"); if (iIndex <= 0) return "/"; string strTemp = strUrl.Substring(iIndex + 2); iIndex = strTemp.IndexOf(@"/"); if (iIndex > 0) return strTemp.Substring(iIndex); else return "/"; } /// <summary> /// 根据Url得到host /// </summary> /// <param name="strUrl">网页url</param> /// <returns></returns> private string GetHostNameBystrUrl(string strUrl) { int iIndex = strUrl.IndexOf(@"//"); if (iIndex <= 0) return ""; string strTemp = strUrl.Substring(iIndex + 2); iIndex = strTemp.IndexOf(@"/"); if (iIndex > 0) return strTemp.Substring(0, iIndex); else return strTemp; } }
//压缩 压缩后 打开文本文件是 一个乱码 static void simple2_1() { string s = "好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好"; for (int i = 0; i < 15; i++) { s += s; }//设置一个字符串,因为要足够大,才能看得出压缩的效果,所有使用for语句 using (FileStream fs = File.OpenWrite("C:\\1.txt"))//定义一个打文件流 { using (GZipStream gz = new GZipStream(fs, CompressionMode.Compress))//定义一个压缩流 { byte[] bytes = Encoding.UTF8.GetBytes(s);//把文字转换成字节 gz.Write(bytes, 0, bytes.Length);//写入文件 } } } //解压 static void simple2_2() { using (FileStream fs = new FileStream("c:\\1.txt", FileMode.Open))//定义打开文件流 { using (GZipStream zp = new GZipStream(fs, CompressionMode.Decompress))//对文件流进行解密 { byte[] b = new byte[1024]; int readbyte=0; using (FileStream outstream = new FileStream("c:\\2.txt", FileMode.Create))//新建一个文件流用于输出 { while((readbyte=zp.Read(b,0,1024))>0) { outstream.Write(b,0,readbyte); } } } } }
如果文件比较大(>2G),那就需要分批复制了。
static async Task Main(string[] args) { string path = Directory.GetCurrentDirectory(); string fromFile = Path.Combine(path, "from.txt"); string toFile = Path.Combine(path, "to.txt"); byte[] buffer = null; FileStream toFS = new FileStream(toFile, FileMode.Create, FileAccess.Write); FileStream fromFS = new FileStream(fromFile, FileMode.Open, FileAccess.Read); int readLength = 0; do { buffer = new byte[1024]; readLength = fromFS.Read(buffer, 0, buffer.Length); toFS.Write(buffer, 0, readLength); } while (readLength > 0); fromFS.Flush(); fromFS.Dispose(); toFS.Flush(); toFS.Dispose(); Console.ReadKey(); }
【.NET流操作】BinaryWriter、BinaryReader
BinaryWriter:以二进制形式将基元类型写入流,并支持用特定的编码写入字符串。
BinartReader:用特定的编码将基元数据类型读作二进制值。
案例:
public class PropertiesSerializer : IDataSerializer<AuthenticationProperties> { private const int FormatVersion = 1; /// <summary> /// Gets the default instance of <see cref="PropertiesSerializer"/>. /// </summary> public static PropertiesSerializer Default { get; } = new PropertiesSerializer(); /// <inheritdoc /> public virtual byte[] Serialize(AuthenticationProperties model) { using (var memory = new MemoryStream()) { using (var writer = new BinaryWriter(memory)) { Write(writer, model); writer.Flush(); return memory.ToArray(); } } } /// <inheritdoc /> public virtual AuthenticationProperties? Deserialize(byte[] data) { using (var memory = new MemoryStream(data)) { using (var reader = new BinaryReader(memory)) { return Read(reader); } } } /// <inheritdoc /> public virtual void Write(BinaryWriter writer, AuthenticationProperties properties) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (properties == null) { throw new ArgumentNullException(nameof(properties)); } writer.Write(FormatVersion); writer.Write(properties.Items.Count); foreach (var item in properties.Items) { writer.Write(item.Key ?? string.Empty); writer.Write(item.Value ?? string.Empty); } } /// <inheritdoc /> public virtual AuthenticationProperties? Read(BinaryReader reader) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (reader.ReadInt32() != FormatVersion) { return null; } var count = reader.ReadInt32(); var extra = new Dictionary<string, string?>(count); for (var index = 0; index != count; ++index) { var key = reader.ReadString(); var value = reader.ReadString(); extra.Add(key, value); } return new AuthenticationProperties(extra); } }
将对象序列化为二进制数组
/// <summary> /// 将一个object对象序列化,返回一个byte[] /// </summary> /// <param name="obj">能序列化的对象</param> /// <returns></returns> public static byte[] ObjectToBytes(object obj) { using (MemoryStream ms = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); return ms.GetBuffer(); } } /// <summary> /// 将一个序列化后的byte[]数组还原 /// </summary> /// <param name="Bytes"></param> /// <returns></returns> public static object BytesToObject(byte[] Bytes) { using (MemoryStream ms = new MemoryStream(Bytes)) { IFormatter formatter = new BinaryFormatter(); return formatter.Deserialize(ms); } }