C#中流的读取器和编写器(BinaryReader与 BinaryWriter ,StreamReader 与 StreamWriter,StringReader 等)详细介绍

原文链接:https://www.cnblogs.com/sexintercourse/p/16647555.html

通常,流用于字节输入和输出。 读取器和编写器类型处理编码字符与字节之间的来回转换,以便流可以完成操作。

下面是一些常用的读取器和编写器类:

  • BinaryReader和 BinaryWriter :用于将基元数据类型作为二进制值进行读取和写入。
  • StreamReader 和 StreamWriter : 用于通过使用编码值在字符和字节之间来回转换来读取和写入字符。
  • StringReader 和 StringWriter:用于从字符串读取字符以及将字符写入字符串中。
  • TextReader和 TextWriter :用作其他读取器和编写器(读取和写入字符和字符串,而不是二进制数据)的抽象基类。

1 先了解一下字符与字节

字节(Byte)是计量单位,表示数据量多少,是计算机信息技术用于计量存储容量的一种计量单位,通常情况下一字节(Byte)等于八位(bit)。

字符(Character)计算机中使用的字母、数字、字和符号,比如'A'、'B'、'$'、'&'等。

一般在英文状态下一个字母或字符占用一个字节,一个汉字用两个字节表示。

字节和字符(图片来源网络)

字节与字符:

  • ASCII 码中,一个英文字母(不分大小写)为一个字节,一个中文汉字为两个字节。
  • UTF-8 编码中,一个英文字为一个字节,一个中文为三个字节。
  • Unicode 编码中,一个英文为一个字节,一个中文为两个字节。
  • 符号:英文标点为一个字节,中文标点为两个字节。例如:英文句号 . 占1个字节的大小,中文句号 。占2个字节的大小。
  • UTF-16 编码中,一个英文字母字符或一个汉字字符存储都需要 2 个字节(Unicode 扩展区的一些汉字存储需要 4 个字节)。
  • UTF-32 编码中,世界上任何字符的存储都需要 4 个字节。

2 BinaryReader 和BinaryWriter

2.1 BinaryReader

用特定的编码将基元数据类型读作二进制值。

2.1.1 常用构造方法和方法

构造方法和方法 描述
BinaryReader(Stream, Encoding, Boolean) 基于所提供的流和特定的字符编码,初始化 BinaryReader 类的新实例,有选择性的打开流。Boolean:如果在释放 BinaryReader对象后保持流处于打开状态,则为 true;否则为 false。
Close() 关闭当前阅读器及基础流
Dispose(Boolean) 释放 BinaryReader类使用的非托管资源,并可以选择释放托管资源。
PeekChar() 返回下一个可用的字符,并且不提升字节或字符的位置。如果没有可用字符或者流不支持查找时为 -1
Read() 从基础流中读取字符,并根据所使用的 Encoding 和从流中读取的特定字符,提升流的当前位置。
Read(Span) 从当前流读取字节序列,并将流中的位置向前移动读取的字节数。
ReadChar(int32) 从当前流中读取指定的字符数,并以字符数组的形式返回数据,然后根据所使用的 Encoding 和从流中读取的特定字符,将当前位置前移。int32:要读取的字符数。
ReadString() 从当前流中读取一个字符串。 字符串有长度前缀,一次 7 位地被编码为整数。
ReadBytes(Int32) 从当前流中读取指定的字节数以写入字节数组中,并将当前位置前移相应的字节数。
BaseStream 获取 BinaryWriter 的基础流。

2.1.2代码示例

using System;
using System.IO;
using System.Text;

class ConsoleApplication
{
    const string fileName = "AppSettings.dat";
    static void Main()
    {
        WriteDefaultValues();
        DisplayValues();
    }
    public static void WriteDefaultValues()//写入默认值的方法
    {//打开文件
        using (var stream = File.Open(fileName, FileMode.Create))
        {//新建一个输入流,并以UTF-8编码,释放BinaryWriter后关闭流
            using (var writer = new BinaryWriter(stream, Encoding.UTF8, false))
            {//写入数据
                writer.Write(1.250F);
                writer.Write(3.657F);
                writer.Write(@"c:\Temp");
                writer.Write(10);
                writer.Write(true);
            }
        }
    }
    public static void DisplayValues()//读取数据
    {
        float aspectRatio1;
        float aspectRatio2;
        string tempDirectory;
        int autoSaveTime;
        bool showStatusBar;
        if (File.Exists(fileName))//如果文件存在
        {//打开文件
            using (var stream = File.Open(fileName, FileMode.Open))
            {//读取文件流
                using (var reader = new BinaryReader(stream, Encoding.UTF8, false))
                {
                    aspectRatio1 = reader.ReadSingle();//从当前流中读取 4 字节浮点值
                    aspectRatio2 = reader.ReadSingle();//从当前流中读取 4 字节浮点值
                    tempDirectory = reader.ReadString();//从当前流中读取一个字符串。 
                    autoSaveTime = reader.ReadInt32();
                    showStatusBar = reader.ReadBoolean();
                }
            }
            Console.WriteLine("Aspect ratio1 set to: " + aspectRatio1);
            Console.WriteLine("Aspect ratio2 set to: " + aspectRatio2);
            Console.WriteLine("Temp directory is: " + tempDirectory);
            Console.WriteLine("Auto save time set to: " + autoSaveTime);
            Console.WriteLine("Show status bar: " + showStatusBar);
        }
    }
}

运行结果

Aspect ratio1 set to: 1.25
Aspect ratio2 set to: 3.657
Temp directory is: c:\Temp
Auto save time set to: 10
Show status bar: True

2.2 BinaryWriter

将二进制中的基元类型写入流并支持用特定的编码写入字符串。

2.2.1 常用构造方法和方法

构造方法和方法 描述
BinaryWriter(Stream, Encoding, Boolean) 基于所提供的流和特定的字符编码,初始化 BinaryWriter 类的新实例,有选择性的打开流。Boolean:如果在释放 BinaryReader对象后保持流处于打开状态,则为 true;否则为 false。
Close() 关闭当前阅读器及基础流
Dispose(Boolean) 释放 BinaryWriter类使用的非托管资源,并可以选择释放托管资源。
Flush() 清理当前编写器的所有缓冲区,使所有缓冲数据写入基础设备。
Seek(Int32, SeekOrigin) 设置当前流中的位置。
Write(Double) 将 8 字节浮点值写入当前流,并将流的位置提升 8 个字节。
Write(String) 将有长度前缀的字符串按 BinaryWriter 的当前编码写入此流,并根据所使用的编码和写入流的特定字符,提升流的当前位置。
Write(Char[], Int32, Int32) 将字符数组部分写入当前流,并根据所使用的 Encoding(可能还根据向流中写入的特定字符),提升流的当前位置。Char[]:包含要写入的数据的字符数组。第一个Int32:要从 chars 中读取且要写入流的第一个字符的索引。第二个int32:要从 chars 中读取且要写入流的字符数。
Write(Byte[], Int32, Int32) 将字节数组区域写入当前流。
Write(Boolean) 将单字节 Boolean 值写入当前流,其中 0 表示 false,1 表示 true。

2.2.2代码示例

 static void Main()
    {
        char[] nemechar = "智能建造小硕".ToCharArray();
        MemoryStream memStream = new MemoryStream();
        BinaryWriter binWriter = new BinaryWriter(memStream);
        //写入内存
        binWriter.Write("微信公众号的名字为: ");
        binWriter.Write( nemechar, 0, nemechar.Length);
        //读取内存
        BinaryReader binReader = new BinaryReader(memStream);
        // 设置当前MemoryStream的开始指针
        memStream.Position = 0;
        // 在控制打印出来
        Console.Write(binReader.ReadString());
        int arraySize = (int)(memStream.Length - memStream.Position);        
        char[] memoryData = new char[arraySize];
        binReader.Read(memoryData, 0, arraySize);
        Console.WriteLine(memoryData);
        Console.WriteLine("名字长度"+memStream.Length);
        Console.WriteLine("读取完后指针的当前位置"+memStream.Position);
        binWriter.Close();
        binReader.Close();
        Console.WriteLine("".PadLeft(40,'-'));
        const int arrayLength = 1000;
        byte[] dataArray = new byte[arrayLength];
        byte[] verifyArray = new byte[arrayLength];
        new Random().NextBytes(dataArray);//随机产生字节数组
        using (BinaryWriter binWriter1 = new BinaryWriter(new MemoryStream()))
        {
            Console.WriteLine("写入数据");
            binWriter1.Write(dataArray, 0, arrayLength);
            using (BinaryReader binReader1 = new BinaryReader(binWriter1.BaseStream))
            //BaseStream就是操作streamreader的,返回的结果就是streamreader
            {
                binReader1.BaseStream.Position = 0;
                if (binReader1.Read(verifyArray, 0, arrayLength) != arrayLength)//写入先后数据的长度是否相等
                {
                    Console.WriteLine("错误写入数据");
                    return;//退出运行
                }
            }
        }
        for (int i = 0; i < arrayLength; i++)
        {//读取前后的两个数据是否一样
            if (verifyArray[i] != dataArray[i])
            {
                Console.WriteLine("错误写入数据");
                return;
            }
        }
        Console.WriteLine("数据被写入并验证");
    }

运行结果:

微信公众号的名字为: 智能建造小硕
名字长度48
读取完后指针的当前位置48
----------------------------------------
写入数据
数据被写入并验证

3 StreamReader 和 StreamWriter

3.1 StreamReader

实现一个 TextReader,使其以一种特定的编码从字节流中读取字符。

StreamReader 默认为 UTF-8 编码,除非另有指定,而不是默认为当前系统的 ANSI 代码页。 UTF-8 正确处理 Unicode 字符,并针对操作系统的本地化版本提供一致的结果。

3.1.1 常用属性和方法

构造方法和方法 描述
StreamReader(Stream, Encoding, Boolean, Int32, Boolean) 为指定的流初始化 StreamReader 类的新实例,带有指定的字符编码、字节顺序标记检测选项和缓冲区大小,有选择性的打开流。Boolean:如果要在文件开头查找字节顺序标记,则为true ;否则为 false。Int32:最小缓冲区大小。Boolean:如果在释放 StreamReader对象后保持流处于打开状态,则为 true;否则为 false。
StreamReader(String, Encoding, Boolean, Int32) 为指定的文件名初始化 StreamReader类的新实例,带有指定字符编码、字节顺序标记检测选项和缓冲区大小。
BaseStream 返回基础流。
CurrentEncoding 获取当前 StreamReader对象正在使用的当前字符编码。
Close() 关闭 StreamReader对象和基础流,并释放与读取器关联的所有系统资源。
Read(Char[], Int32, Int32) 从指定的索引位置开始将来自当前流的指定的最多字符读到缓冲区。第一个Int32;开始写入的 buffer 的索引。第二个Int32:最多读取的字符数。
ReadLine() 从当前流中读取一行字符并将数据作为字符串返回。
Dispose() 释放由 TextReader对象使用的所有资源。
ReadToEnd() 读取来自流的当前位置到结尾的所有字符。

3.1.2 代码示例

 public static void Main()
    {
        try
        { //创建一个StreamReader实例读取文件
            using (StreamReader sr = new StreamReader("G:\\Desktop\\archive1\\MyTest.txt"))
            {
                string line;
                //一行行读取文件并在控制台输出
                while ((line = sr.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
            }
            MemoryStream ms =  new MemoryStream();
            StreamWriter streamWriter = new StreamWriter(ms);           
            streamWriter.Write("智能建造小硕\n");    
            streamWriter.Flush();
            ms.Position = 0;
            StreamReader streamReader = new StreamReader(ms);
            Console.WriteLine(streamReader.EndOfStream);
            String rs =streamReader.ReadLine();
            Console.WriteLine(rs);            
        }
        catch (Exception e)
        {
            Console.WriteLine("不可读");
            Console.WriteLine(e.Message);
        }
    }

运行结果

This is some textThis is some more text,
and this is on a new line

The following is a subset of characters:

  
123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{
False
智能建造小硕

3.2 StreamWriter

实现一个 TextWriter,使其以一种特定的编码向流中写入字符。

3.2.1 常用属性和方法

构造方法和方法 描述
StreamWriter(Stream, Encoding, Boolean, Int32, Boolean) 使用指定的编码和缓冲区大小,为指定的流初始化 StreamWriter 类的新实例,并可以选择保持流处于打开状态。Boolean:如果要在文件开头查找字节顺序标记,则为true ;否则为 false。Int32:最小缓冲区大小。Boolean:如果在释放 StreamReader对象后保持流处于打开状态,则为 true;否则为 false。
StreamWriter(String, Encoding, FileStreamOptions) 使用指定的编码并配置指定的 对象,为指定文件初始化 StreamWriter 类的新 FileStreamOptions实例。String:要写入的完整文件路径。
BaseStream 返回基础流。
Encoding 获取在其中写入输出的 Encoding
Close() 关闭 StreamWriter对象和基础流,并释放与读取器关联的所有系统资源。
Write(Char[], Int32, Int32) 将字符的子数组写入流。第一个Int32;开始写入的 buffer 的索引。第二个Int32:最多读取的字符数。
ReadLine() 从当前流中读取一行字符并将数据作为字符串返回。
Dispose() 释放由 TextWriter对象使用的所有资源。
Write(String) 将字符串写入流
WriteLine() 将行终止符写入文本流。

3.1.2 代码示例

 static void Main(string[] args)
    {
        //获取C盘下的子文件目录
        DirectoryInfo cDirs = new DirectoryInfo(@"G:\Desktop\archive1");
        //* (星号):在该位置的零个或多个字符。?(问号):在该位置的零个或一个字符。
        FileInfo[] directoryInfos = cDirs.GetFiles("*",SearchOption.AllDirectories);
        // 将目录名写入文件
        using (StreamWriter sw = new StreamWriter("G:\\Desktop\\archive1\\Test3.txt"))
        {
            foreach (FileInfo dir in directoryInfos)
            {
                sw.WriteLine(dir.FullName);
            }
        }
        // 读取文件的每一行
        string line = "";
        using (StreamReader sr = new StreamReader("G:\\Desktop\\archive1\\Test3.txt"))
        {
            while ((line = sr.ReadLine()) != null)
            {
                Console.WriteLine(line);
            }
        }
    }

运行结果

G:\Desktop\archive1\AppSettings.dat
G:\Desktop\archive1\Test3.txt
G:\Desktop\archive1\新建文件夹\MyTest.txt
G:\Desktop\archive1\新建文件夹\MyTest1.txt

其它两对StringReader 与 StringWriter TextReader与 TextWriter 可阅读参考文献:

更多I/O流通用案例:

posted @ 2023-10-12 09:58  yinghualeihenmei  阅读(185)  评论(0编辑  收藏  举报