C# - 流 Stream

C# 包括以下标准 IO(输入/输出)类,用于从文件、内存、网络、隔离存储等不同来源读取/写入。

Stream:System.IO.Stream 是一个抽象类,它提供了将字节(读取、写入等)传输到源的标准方法。它就像一个包装类来传输字节。需要从特定源读取/写入字节的类必须实现 Stream 类。

以下类继承 Stream 类以提供从特定源读取/写入字节的功能:

FileStream: 从/向物理文件读取或写入字节,无论它是 .txt、.exe、.jpg 还是任何其他文件。 FileStream 派生自 Stream 类。

MemoryStream:MemoryStream 读取或写入存储在内存中的字节。

BufferedStream:BufferedStream 从其他流读取或写入字节以提高某些 I/O 操作的性能。

NetworkStream:NetworkStream 从网络套接字读取或写入字节。

PipeStream:PipeStream 从不同进程读取或写入字节。

CryptoStream:CryptoStream 用于将数据流链接到加密转换。

下图显示了流类的层次结构:

流 Readers and Writers

StreamReader:StreamReader 是一个辅助类,用于通过使用编码值将字节转换为字符来从 Stream 中读取字符。 它可用于从不同的流(如 FileStream、MemoryStream 等)读取字符串(字符)。

StreamWriter:StreamWriter 是一个帮助类,用于通过将字符转换为字节来将字符串写入 Stream。 它可用于将字符串写入不同的流,例如 FileStream、MemoryStream 等。

BinaryReader:BinaryReader 是一个帮助类,用于从字节读取原始数据类型。

BinaryWriter:BinaryWriter 以二进制形式写入原始类型。

上图显示 FileStream 从物理文件中读取字节,然后 StreamReader 通过将这些字节转换为字符串来读取字符串。 同理,StreamWriter 将字符串转换为字节写入 FileStream,然后 FileStream 将字节写入物理文件。 因此,FileStream 处理字节,而 StreamReader 和 StreamWriter 处理字符串。

要记住的要点:

  • Stream 是一个抽象类,用于从不同来源传输字节。 它是所有其他类的基类,可以将字节读/写到不同的来源。
  • FileStream 类提供字节到物理文件的读写功能。
  • Reader & writer 类提供从 Stream 类(FileStream、MemoryStream 等)读取字节并将字节转换为适当编码的功能。
  • StreamReader 提供了一个辅助方法,通过将字节转换为字符串来从 FileStream,或者其它Stream 读取字符串。
  • StreamWriter 提供了一种辅助方法,通过将字符串转换为字节来将字符串写入 FileStream, 或者其它Stream。

示例1 MemoryStream

using System;
using System.IO;

namespace Malema.net
{
    class Program
    {
        static void Main(string[] args)
        {
            var ms = new MemoryStream();
            Console.WriteLine(ms.Length);
            var sw = new StreamWriter(ms);
            sw.WriteLine("你好 测试stream");
            sw.Flush(); // 清空缓冲区,把缓冲的东西扔到底层流
            Console.WriteLine($"{ms.Length} {ms.Position}");

            ms.Seek(0, SeekOrigin.Begin);//把流的位置设回到0否则下面是读不到东西的。
            using (var sr = new StreamReader(ms))
            {
                var line = sr.ReadLine();
                Console.WriteLine(line); //你好 测试stream
            }
        }
    }
}

示例2 不同编码的情况

using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace Malema.net
{
    class Program
    {
        static async Task Main(string[] args)
        {
            //.net core5.0下默认没有 GB2312的编码。等用下面一行来注册
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 
            var ms = new MemoryStream();
            Console.WriteLine(ms.Length);
            var sw = new StreamWriter(ms, Encoding.GetEncoding("GB2312")); // 写入的是 GB2312编码
            sw.WriteLine("你好 测试stream");
            sw.Flush(); // 清空缓冲区,把缓冲的东西扔到底层流
            Console.WriteLine($"{ms.Length} {ms.Position}");

            ms.Seek(0, SeekOrigin.Begin);//把流的位置设回到0否则下面是读不到东西的。
            using (var sr = new StreamReader(ms, Encoding.UTF8)) //读出来用UTF-8
            {
                var line = sr.ReadLine();
                Console.WriteLine(line);//这边看到是乱码了 ??? ????stream 
            }
        }
    }
}

输出乱码了。 为什么能看到stream。因为两个编码都兼容了ASCII。

示例3 读取 网络上的内容

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

namespace Malema.net
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var client = new HttpClient();
            var stream = await client.GetStreamAsync("https://www.malema.net");
            using (var sr = new StreamReader(stream))
            {
                var lines = sr.ReadToEnd();
                Console.WriteLine(lines);
            }
        }
    }
}

只是演示StreamReader,实际上我们会用 client.GetStringAsyncclient.GetAsync 这两个更方便。

DES加密解密

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Malema.net
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var encrypted = Encrypt("asdfsdf", "abcdefgg", "12345678");
            Console.WriteLine(encrypted);//OiYN2rjkuzE=
        }

        public static string Encrypt(string sourceString, string key, string iv)
        {
            try
            {
                byte[] btKey = Encoding.UTF8.GetBytes(key);
                byte[] btIV = Encoding.UTF8.GetBytes(iv);
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                using (MemoryStream ms = new MemoryStream())
                {
                    byte[] inData = Encoding.UTF8.GetBytes(sourceString);
                    try
                    {
                        using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(btKey, btIV), CryptoStreamMode.Write))
                        {
                            cs.Write(inData, 0, inData.Length);
                            cs.FlushFinalBlock();
                        }
                        return Convert.ToBase64String(ms.ToArray());
                    }
                    catch
                    {
                        return sourceString;
                    }
                }
            }
            catch { }
            return "DES加密出错";
        }

        public static string Decrypt(string encryptedString, string key, string iv)
        {
            byte[] btKey = Encoding.UTF8.GetBytes(key);
            byte[] btIV = Encoding.UTF8.GetBytes(iv);
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            using (MemoryStream ms = new MemoryStream())
            {
                byte[] inData = Convert.FromBase64String(encryptedString);
                try
                {
                    using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(btKey, btIV), CryptoStreamMode.Write))
                    {
                        cs.Write(inData, 0, inData.Length);
                        cs.FlushFinalBlock();
                    }
                    return Encoding.UTF8.GetString(ms.ToArray());
                }
                catch
                {
                    return encryptedString;
                }
            }
        }
    }
}

上一篇:C# 扩展方法
下一篇:C# 文件操作
最近更新的
...