ZetCode

C# StreamReader

最后修改于 2025 年 4 月 20 日

本教程介绍了如何在 C# 中使用 StreamReader 类从文件中读取文本数据。 StreamReader 提供了从具有各种编码的流中读取字符数据的方法。

StreamReader 类以特定的编码从字节流中读取字符。 它继承自 TextReader,专为高效读取文本文件而设计。

StreamReader 自动处理不同的文本编码,如 UTF-8、Unicode 和 ASCII。 它提供了读取行、整个文件或逐字符处理的方法。

StreamReader 基础示例

此示例演示了如何使用 StreamReader 逐行读取文本文件。 它展示了处理文本文件的最简单方法。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "example.txt";
        
        // Create a sample file first
        File.WriteAllText(filePath, "First line\nSecond line\nThird line");

        // Read the file line by line
        using (StreamReader reader = new StreamReader(filePath))
        {
            string line;
            int lineNumber = 1;
            
            while ((line = reader.ReadLine()) != null)
            {
                Console.WriteLine($"Line {lineNumber}: {line}");
                lineNumber++;
            }
        }
    }
}

该程序首先创建一个包含三行的示例文本文件。 然后它使用 StreamReader 逐行读取文件。 当到达文件末尾时,ReadLine 方法返回 null。

using 语句确保正确清理资源。 每行都打印其行号。 这种模式在 C# 中很常见于文本文件处理。

一次性读取整个文件

StreamReader 可以使用 ReadToEnd 一次性读取整个文件。 这对于可以放入内存的小文件很有用。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "document.txt";
        
        // Create sample file
        File.WriteAllText(filePath, "This is the entire content\nof the text file.");

        // Read entire file
        using (StreamReader reader = new StreamReader(filePath))
        {
            string content = reader.ReadToEnd();
            Console.WriteLine("File content:");
            Console.WriteLine(content);
            
            Console.WriteLine($"\nTotal characters: {content.Length}");
        }
    }
}

ReadToEnd 读取从当前位置到流结尾的所有字符。 它返回一个包含整个文件内容的字符串。

这种方法很简单,但应谨慎用于大型文件。 对于大文件,逐行读取更节省内存。

逐字符读取

StreamReader 提供了 Read 方法来读取单个字符。 此示例显示了如何逐字符处理文件。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "chars.txt";
        File.WriteAllText(filePath, "ABC\n123");

        using (StreamReader reader = new StreamReader(filePath))
        {
            int ch;
            int count = 0;
            
            while ((ch = reader.Read()) != -1)
            {
                count++;
                Console.WriteLine($"Char {count}: {(char)ch} (Unicode: {ch})");
            }
            
            Console.WriteLine($"\nTotal characters read: {count}");
        }
    }
}

Read 方法返回下一个字符作为整数,或者在文件末尾返回 -1。 我们将整数转换为 char 以进行显示。

这种方法对于需要单独检查每个字符的底层文本处理非常有用。 请注意,它包括换行符。

指定文件编码

StreamReader 可以处理不同的文本编码。 此示例演示了如何读取具有特定编码(如 UTF-8 和 Unicode)的文件。

Program.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        string filePath = "unicode.txt";
        
        // Create file with Unicode encoding
        File.WriteAllText(filePath, "Привет мир!", Encoding.Unicode);

        // Read with explicit encoding
        using (StreamReader reader = new StreamReader(filePath, Encoding.Unicode))
        {
            string content = reader.ReadToEnd();
            Console.WriteLine("Read content: " + content);
            
            Console.WriteLine("\nFirst character: " + content[0]);
            Console.WriteLine("Encoding: " + reader.CurrentEncoding.EncodingName);
        }
    }
}

该示例使用 Unicode 编码写入文本,并使用相同的编码将其读回。 CurrentEncoding 显示正在使用的编码。

读取非 ASCII 文本文件时,始终指定正确的编码。 默认编码是 UTF-8,但许多旧系统使用其他编码。

查看下一个字符

StreamReader 的 Peek 方法允许查看下一个字符而不消耗它。 这对于解析场景非常有用。

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = "data.txt";
        File.WriteAllText(filePath, "ABC\n123");

        using (StreamReader reader = new StreamReader(filePath))
        {
            Console.WriteLine("Peek first: " + (char)reader.Peek());
            Console.WriteLine("Read first: " + (char)reader.Read());
            
            Console.WriteLine("Peek again: " + (char)reader.Peek());
            Console.WriteLine("Read again: " + (char)reader.Read());
        }
    }
}

Peek 返回下一个字符而不推进位置。 它在文件末尾返回 -1,就像 Read 一样。

当您需要在流中向前看以决定如何处理下一个字符时,此方法特别有用,例如在解析器中。

使用缓冲区读取

对于性能关键型应用程序,StreamReader 可以将字符块读入缓冲区。 此示例显示了基于缓冲区的读取。

Program.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        string filePath = "largefile.txt";
        
        // Create a large sample file
        var sb = new StringBuilder();
        for (int i = 0; i < 1000; i++)
        {
            sb.AppendLine($"Line {i + 1}");
        }
        File.WriteAllText(filePath, sb.ToString());

        // Read with buffer
        char[] buffer = new char[128];
        using (StreamReader reader = new StreamReader(filePath))
        {
            int charsRead;
            int totalChars = 0;
            
            while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
            {
                totalChars += charsRead;
                Console.Write($"Read {charsRead} chars: ");
                Console.WriteLine(new string(buffer, 0, Math.Min(20, charsRead)) + "...");
            }
            
            Console.WriteLine($"\nTotal characters read: {totalChars}");
        }
    }
}

Read 重载使用来自流的数据填充字符缓冲区。 它返回实际读取的字符数。

对于大型文件,缓冲读取比逐字符处理更有效。 可以调整缓冲区大小以获得最佳性能。

从 MemoryStream 读取

StreamReader 可以从任何 Stream 读取,包括 MemoryStream。 此示例显示了从内存中读取文本数据。

Program.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        // Create text in memory
        string text = "This text is in memory\nSecond line\nThird line";
        byte[] bytes = Encoding.UTF8.GetBytes(text);
        
        // Read from MemoryStream
        using (var memoryStream = new MemoryStream(bytes))
        using (var reader = new StreamReader(memoryStream))
        {
            Console.WriteLine("Reading from MemoryStream:");
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                Console.WriteLine("> " + line);
            }
        }
    }
}

该示例将字符串转换为字节,从这些字节创建 MemoryStream,然后使用 StreamReader 读取它。 这种模式对于处理从网络或其他来源接收的文本数据非常有用。

StreamReader 对 MemoryStream 的工作方式与对文件流的工作方式相同,展示了它在不同流源中的灵活性。

来源

StreamReader 类文档

本教程介绍了在 C# 中使用 StreamReader 读取文本数据,包括逐行读取、编码、缓冲和内存流。 StreamReader 可用于所有文本处理需求。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。 迄今为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程