5. 使用读取器和写入器

使用FileStream类读写文本文件,需要使用字节数组,处理前一节描述的编码。有更简单的方法:使用读写器和写入器。可以使用StreamReader和StreamWriter类读写FileStream,不需要处理字节数组和编码,比较轻松。

这是因为这些类工作的级别比较高,特别适合于读写文本。它们实现的方法可以根据流的内容,自动检测出停止读取文本较方便的位置。特别是:

  • 这些类实现的方法(StreamReader.ReadLine和StreamWriter.WriteLine)可以一次读写一行文本。在读取文件时,流会自动确定下一个回车符的位置,并在该处停止读取。在写入文件时,流会自动把回车符和换行符追加到文本的末尾。
  • 使用StreamReader和StreamWriter类,就不需要担心文件中使用的编码方式。

ReaderWriterSamples的示例代码使用下面的名称空间:

System

System.Collections.Generic

System.Globalization

System.IO

System.Linq

System.Text

System.Threading.Tasks

1. StreamReader类

先看看StreamReader,将前面的示例转换为读取文件以使用StreamReader。它现在看起来容易的多。StreamReader的构造函数接收FileStream。使用EndOfStream属性可以检查文件的末尾,使用ReadLine方法读取文本行:

        static void ReadFileUsingReader(string fileName)
        {
            var stream = new FileStream(fileName,FileMode.Open,FileAccess.Read,FileShare.Read);
            using (var reader = new StreamReader(stream:stream))
            {
                while (!reader.EndOfStream)
                {
                  string line =  reader.ReadLine();
                    Console.WriteLine(line);
                }
            }
        }

不再需要处理字节数组和编码。然而注意,StreamReader默认使用UTF-8编码。指定另一个构造函数,可以让StreamReader使用文件中序言定义的编码:

            var reader2 = new StreamReader(stream:stream, detectEncodingFromByteOrderMarks:true);

也可以显示地指定编码:

            var reader3 = new StreamReader(stream:stream,encoding:Encoding.Unicode);

其他构造函数允许设置要使用的缓冲区;默认为1024个字节。此外,还可以指定关闭读取器时不应该关闭底层流。默认情况下,关闭读取器时(使用Dispose方法),会关闭底层流。

不显示实例化新的StreamReader,而可以使用File类的OpenText方法创建StreamReader:

            StreamReader reader4 = File.OpenText(fileName);

对于读取文件的代码片段,该文件使用ReadLine方法逐行读取。StreamReader还允许在流中使用ReadToEnd从光标的位置读取完整的文件:

            string content = reader2.ReadToEnd();

StreamReader还允许把内容读入一个字符串数组。这类似于Stream类的Read方法;它不读入字节数组,而是读入char数组。记住,char类型使用两个字节。这适合于16位Unicode,但不适合于UTF-8,其中,一个字符的长度可以是1至6个字节:

            int nCharsRead = reader2.Read(buffer:charArray, index:0, count:nChars);

2. StreamWriter类

StreamWriter的工作方式与StreamReader相同,只是StreamWriter仅用于写入文件(或写入另一个流)。下面的代码片段传递FileStream,创建了一个StreamWriter。然后把传入的字符串数组写入流:

        static void WriteFileUsingWriter(string fileName,string[] lines)
        {
            var outputStream = File.OpenWrite(path:fileName);
            using (var writer = new StreamWriter(outputStream))
            {
                byte[] preamble = Encoding.UTF8.GetPreamble();
                outputStream.Write(preamble,0,preamble.Length);
                writer.Write(lines);
            }
        }

注意:经测试,无法直接写入字符串数组,可以写入字符串或char[]数组。

记住,StreamWriter默认使用UTF-8格式写入文本内容。通过在构造函数中设置Encoding对象,可以定义替代的内容。另外,类似于StreamReader的构造函数,StreamWriter允许指定缓冲区的大小,以及关闭写入器时是否不应该关闭底层流。

StreamWriter的Write()方法定义了17个重载方法,允许传递字符串和一些.NET数据类型。请记住,使用传递.NET数据类型的方法,这些都会使用指定的编码变成字符串。要以二进制格式写入数据类型,可以使用下面介绍的BinaryWriter。

3. 读写二进制文件

读写二进制文件的一种选择是直接使用流类型;在这种情况下,最好使用字节数组执行读写操作。另一个选择是使用为这个场景定义的读写器和写入器;BinaryReader和BinaryWriter。使用它们的方式类似于使用StreamReader和StreamWriter,但BinaryReader和BinaryWriter不使用任何编码。文件使用二进制格式而不是文本格式写入。

与Stream类型不同,BinaryWriter为Write()方法定义了18个重载版本。重载版本接受不同的类型,如下面的代码片段所示,它写入double、int、long和string:

        static void WriteFileUsingBinaryWriter(string fileName)
        {
            var outputStream = File.Create(fileName);
            using (var writer = new BinaryWriter(outputStream))
            {
                double d = 47.47;
                int i = 42;
                long l = 987654321;
                string s = "sample";
                writer.Write(d);
                writer.Write(i);
                writer.Write(l);
                writer.Write(s);
            }
        }

为了再次读取文件,可以使用BinaryReader。这个类定义的方法会读取所有不同的类型。如ReadDouble、ReadIn32、ReadInt64和ReadString,如下所示:

        static void ReadFileUsingBinaryReader(string fileName)
        {
            var inputStream = File.Open(fileName,FileMode.Open,FileAccess.Read);
            using (var reader = new BinaryReader(inputStream))
            {
                double d = reader.ReadDouble();
                int i = reader.ReadInt32();
                long l = reader.ReadInt64();
                string s = reader.ReadString();
                Console.WriteLine($"d: {d}, i: {i}, l: {l}, s: {s}");
            }
        }

读取文件的顺序必须完全匹配写入的顺序。创建自己的二进制格式时,需要知道存储的内容和方式,并用相应的方式读取。旧的微软Word文档使用二进制文件格式,而新的docx文件扩展是ZIP文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值