C# 流Stream详解(1)——读写txt和二进制文件

本文详细介绍了C#中通过多种方式如StreamReader/StreamWriter、TextReader/TextWriter、FileStream以及File类等操作txt文本文件,同时探讨了二进制文件的读写,包括BinaryWriter/BinaryReader和MemoryStream的使用,以及序列化工具的应用。

【读写txt文件】

电脑手机上有各种各样的文件,例如视频文件、图片文件、文本文件,其中读写txt文件是最简单的,有多种方式,

使用StreamReader和StreamWriter

//读取文件
string path = @"C:\example.txt"; // 文件路径
using (StreamReader reader = new StreamReader(path))//使用using语句来确保资源被正确释放,以避免资源泄漏
{
    string line;
    while ((line = reader.ReadLine()) != null) // 逐行读取文件内容,每次读取一行,读取到末尾的时候为空
    {
        Console.WriteLine(line); // 输出每行内容到控制台
    }
}

//写入文件
string path = @"C:\example.txt"; // 文件路径
using (StreamWriter writer = new StreamWriter(path))
{
    string content = "Hello, World!"; // 要写入文件的内容
    writer.WriteLine(content); // 写入一行内容到文件
}

使用TextReader和TextWriter 

//读取文件
string path = @"C:\example.txt"; // 文件路径
using (TextReader reader = new StreamReader(path))
{
    string line;
    while ((line = reader.ReadLine()) != null) // 逐行读取文件内容
    {
        Console.WriteLine(line); // 输出每行内容到控制台
    }
}

//写入文件
string path = @"C:\example.txt"; // 文件路径
using (TextReader reader = new StreamReader(path))
{
    string line;
    while ((line = reader.ReadLine()) != null) // 逐行读取文件内容
    {
        Console.WriteLine(line); // 输出每行内容到控制台
    }
}

 使用FileStream

//读取文件
string path = @"C:\example.txt"; // 文件路径
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
    using (StreamReader reader = new StreamReader(fs))
    {
        string line;
        while ((line = reader.ReadLine()) != null) // 逐行读取文件内容
        {
            Console.WriteLine(line); // 输出每行内容到控制台
        }
    }
}


//写入文件
string path = @"C:\example.txt"; // 文件路径
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
    using (StreamWriter writer = new StreamWriter(fs))
    {
        string content = "Hello, World!"; // 要写入文件的内容
        writer.WriteLine(content); // 写入一行内容到文件
    }
}

使用File类提供的静态方法

上面几种方法代码都很长,一般来说我们几乎不会使用这些方法,使用File类提供的静态方法更便捷一些。如果文件非常大,还是要用上面的方法读文件,否则一次性读进来,内存会爆。

如果期望追加写入,还是要用上面的方法,StreamWriter的参数设置为true就好,例如StreamWriter sw = new StreamWriter(filePath, true);

//读取文件
string path = @"C:\example.txt"; // 文件路径
string content = File.ReadAllText(path); // 读取整个文件内容
Console.WriteLine(content); // 输出文件内容到控制台

//写入文件
string path = @"C:\example.txt"; // 文件路径
string content = "Hello, World!"; // 要写入文件的内容
File.WriteAllText(path, content); // 将内容写入文件

//上面是一次性读取写入,得到的对象是一个非常大的string,但有时我们需要逐行处理,就要逐行读取写入
string path = @"C:\example.txt"; // 文件路径
string[] lines = File.ReadAllLines(path); // 读取所有行
foreach (string line in lines)
{
    Console.WriteLine(line); // 在控制台输出每一行
}

string path = @"C:\example.txt"; // 文件路径
string[] lines = { "第一行内容", "第二行内容", "第三行内容" }; // 字符串数组,每个元素将成为一行
File.WriteAllLines(path, lines); // 将字符串数组中的所有元素写入到文件中

文本编码

如果读出来的内容是乱码,建议了解文本编码,在读取和写入文本时都可以传递文本编码参数。

【读写二进制文件】 

使用BinaryWriter和BinaryReader

我们知道在磁盘上只会存储二进制数据,文本文件最后也会被保存为二进制文件,我们调用接口读取和写入时虽然用的是string,但到底层一定是byte[]。这就涉及到string到byte[]的编码和byte[]到string的解码,只不过对于文本文件而言,有确定的编码解码规则,我们不需要关心。

而读写二进制文件,需要你自己设置编码解码规则。编码解码的类型不止是string,可能是各种类型的。

//写入文件
using (BinaryWriter writer = new BinaryWriter(File.Open("file.bytes", FileMode.Create)))
{    
    bool boolValue = true;
    writer.Write(boolValue);

    int intValue = 123;
    writer.Write(intValue);

    float floatValue = 3.14f;
    writer.Write(floatValue);

    double doubleValue = 3.1415926;
    writer.Write(doubleValue);

    char charValue = 'A';
    writer.Write(charValue);

    string content = "永恒之星";
    byte[] bytes = Encoding.UTF8.GetBytes(content);
    writer.Write(bytes.Length); // 写入字符串长度
    writer.Write(bytes); // 写入字符串字节数组
}

 读取文件时按照写入的顺序一个个读取即可。

//读取文件
        using (BinaryReader reader = new BinaryReader(File.Open("file.bytes", FileMode.Open)))
        {
            bool boolValue = reader.ReadBoolean();
            Debug.Log(boolValue);

            int intValue = reader.ReadInt32();
            Debug.Log(intValue);

            float floatValue = reader.ReadSingle();
            Debug.Log(floatValue);

            double doubleValue = reader.ReadDouble();
            Debug.Log(doubleValue);

            char charValue = reader.ReadChar();
            Debug.Log(charValue);

            int length = reader.ReadInt32();
            byte[] bytes = reader.ReadBytes(length);
            string content = Encoding.UTF8.GetString(bytes);
            Debug.Log(content);
        }

使用MemoryStream

上面的问题在于是一次次读写的,会有多次IO开销,可以借助MemoryStream将文件内容先一次性读写到内存中,然后再读写到磁盘中。

另外,我们读写数据时是一行行代码读写的,如果有一万个数据,当然不可能写一万行代码,所以对同类型的数据需要将数据个数也写入,用for循环减少代码量。

        //写入文件
        using (MemoryStream ms = new MemoryStream())
        {
            using (BinaryWriter writer = new BinaryWriter(ms))
            {

                bool boolValue = true;
                writer.Write(boolValue);

                int count = 5;
                writer.Write(count);
                for (int i = 0; i < count; i++)
                {
                    int intValue = 123;
                    writer.Write(intValue);
                }

                float floatValue = 3.14f;
                writer.Write(floatValue);

                double doubleValue = 3.1415926;
                writer.Write(doubleValue);

                char charValue = 'A';
                writer.Write(charValue);

                string content = "永恒之星";
                byte[] bytes = Encoding.UTF8.GetBytes(content);
                writer.Write(bytes.Length); // 写入字符串长度
                writer.Write(bytes); // 写入字符串字节数组
            }
            File.WriteAllBytes("file.bytes", ms.ToArray());//一次性写入磁盘
        }

        //读取文件
        using (MemoryStream ms = new MemoryStream(File.ReadAllBytes("file.bytes")))//一次性从磁盘读取数据
        {
            using (BinaryReader reader = new BinaryReader(ms))
            {
                bool boolValue = reader.ReadBoolean();
                Debug.Log(boolValue);

                int count = reader.ReadInt32();
                for (int i = 0; i < count; i++)
                {
                    int intValue = reader.ReadInt32();
                    Debug.Log(intValue);
                }

                float floatValue = reader.ReadSingle();
                Debug.Log(floatValue);

                double doubleValue = reader.ReadDouble();
                Debug.Log(doubleValue);

                char charValue = reader.ReadChar();
                Debug.Log(charValue);

                int length = reader.ReadInt32();
                byte[] bytes = reader.ReadBytes(length);
                string content = Encoding.UTF8.GetString(bytes);
                Debug.Log(content);
            }
        }

拓展

如果我们有很多不同类型的数据需要写到不同的二进制文件中,而且后期的数据结构还可能会修改,那么每次自己读写就非常繁琐,维护成本很高。我们需要借助些序列化工具帮忙读写,我们只需要定义好数据结构,并填充数据即可。这些工具有BinaryFomatter、ProtoBuf、FlatBuffer,更具需求选择合理的工具。

1.1 什么是Stream? 1.2 什么是字节序列? 1.3 Stream的构造函数 1.4 Stream的重要属性及方法 1.5 Stream的示例 1.6 Stream异步读写 1.7 Stream 其子类的类图 2.1 为什么要介绍 TextReader? 2.2 TextReader的常用属性方法 2.3 TextReader 示例 2.4 从StreamReader想到多态 2.5 简单介绍下Encoding 编码 2.6 StreamReader 的定义及作用 2.7 StreamReader 类的常用方法属性 2.8 StreamReader示例 3.1 为何介绍TextWriter? 3.2 TextWriter的构造,常用属性方法 3.3 IFormatProvider的简单介绍 3.4 如何理解StreamWriter? 3.5 StreamWriter属性 3.6 StreamWriter示例 4.1 如何去理解FileStream? 4.2 FileStream的重要性 4.3 FileStream常用构造函数(重要) 4.4 非托管参数SafeFileHandle简单介绍 4.5 FileStream常用属性介绍 4.6 FileStream常用方法介绍 4.7 FileStream示例1:*文件的新建拷贝(主要演示文件同步异步操作) 4.8 FileStream示例2:*实现文件本地分段上传 5.1 简单介绍一下MemoryStream 5.2 MemoryStreamFileStream的区别 5.3 通过部分源码深入了解下MemoryStream 5.4 分析MemorySteam最常见的OutOfMemory异常 5.5 MemoryStream 的构造 5.6 MemoryStream 的属性 5.7 MemoryStream 的方法 5.8 MemoryStream 简单示例 : XmlWriter中使用MemoryStream 5.9 MemoryStream 简单示例 :自定义一个处理图片的HttpHandler 6.1 简单介绍一下BufferedStream 6.2 如何理解缓冲区? 6.3 BufferedStream的优势 6.4 从BufferedStream 中学习装饰模式 6.5 如何理解装饰模式 6.6 再次理解下装饰模式在Stream中的作用 6.7 BufferedStream的构造 6.8 BufferedStream的属性 6.9 BufferedStream的方法 6.10 简单示例:利用socket 读取网页并保存在本地 7.1 NetworkStream的作用 7.2 简单介绍下TCP/IP 协议相关层次 7.3 简单说明下 TCPUDP的区别 7.4 简单介绍下套接字(Socket)的概念 7.5 简单介绍下TcpClient,TcpListener,IPEndPoint类的作用 7.6 使用NetworkStream的注意事项局限性 7.7 NetworkStream的构造 7.8 NetworkStream的属性 7.9 NetworkStream的方法 7.10 NetwrokStream的简单示例 7.11 创建一个客户端向服务端传输图片的小示例 版权归作者所有,仅供学习参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值