【.NET流操作】流装饰器

2022/6/6 23:21:57

本文主要是介绍【.NET流操作】流装饰器,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

比如压缩流、加密流,这些流不仅有Stream的所有特征,还有自己的个性。它们不仅继承Stream类,还引用Stream类。这些通过"装饰器模式"来实现的流包括:BufferedStream, DeflateStream, GZipStream, CryptoStream, AuthenticateStream.

BufferedStream

BufferedStream类是一个流的包装类,对流进行”缓存功能的扩展包装”,它是一个装饰器类
为什么MemoryStream 同样也是在内存中对流进行操作,和BufferedStream有什么区别呢?BufferedStream并不是将所有内容都存放到内存中,而MemoryStream则是。BufferedStream必须跟其他流如FileStream结合使用,而MemoryStream则不用

构造函数

  • BufferedStream(Stream)
    其实BufferedStream的构造主要功能还是设置缓冲区大小,如果没有指定则默认是用4096字节的进行初始化
  • BufferedStream(Stream, Int32)
    第二个参数是手动指定缓冲区大小

属性

  • CanRead 已重写。获取一个值,该值指示当前流是否支持读取。
    如果流支持读取,则为 true;如果流已关闭或是通过只写访问方式打开的,则为 false。
  • CanSeek 已重写。获取一个值,该值指示当前流是否支持查找。
    如果流支持查找,则为 true;如果流已关闭或者如果流是由操作系统句柄(如管道或到控制台的输出)构造的,则为 false。
    如果从 Stream 派生的类不支持查找,则对 Length、SetLength、Position 和 Seek 的调用将引发 NotSupportedException。
    如果该流已关闭,此属性将返回 false。
  • CanWrite 已重写。获取一个值,该值指示当前流是否支持写入。
    如果流支持写入,则为 true;如果流已关闭或是通过只读访问方式打开的,则为 false。 如果从 Stream 派生的类不支持写入,
    则调用 SetLength、Write 或 WriteByte 将引发 NotSupportedException。 如果该流已关闭,此属性将返回 false。
  • Length 已重写。获取流长度,长度以字节为单位。
  • Position 已重写。获取当前流内的位置。
    • get 访问器调用 Seek 获取基础流中的当前位置,然后根据缓冲区中的当前位置调整此值。
    • set 访问器将以前写入缓冲区的所有数据都复制到基础流中,然后调用 Seek。

案例

点击查看代码
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;
        }

    }

GZipStream(压缩流)

案例

        //压缩  压缩后 打开文本文件是 一个乱码
        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、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);
        }
    }

BinaryFormatter

将对象序列化为二进制数组

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


这篇关于【.NET流操作】流装饰器的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程