• 【C#教程16/16】: 输入输出


    目录

    一、提要

    二、C# input和output

    2.1 C# 流

    2.2 处理异常(exceptions)

    2.3 发行资源(Releasing resources)

    2.4 文本文件示例

    三、读取整个文件 (File.ReadAllText)

    四、逐行读取文件( File.ReadAllLines)

    4.1 逐行读取

    4.2 生成逐行文件( create file )

    五、获取文件建立时间、最后写入、最后访问时间

    六、拷贝文件

    七、 异常接口(IDisposable interface)

    八、用using 定义语句

    九、using 声明

    十、内存流MemoryStream

    十一、读取流( StreamReader)

    十二、行统计(count lines)

    十三、流写入( StreamWriter)

    十四、文件流(FileStream)

    十五、xml文件读取(XmlTextReader)

    十六、生成和转移create, move directory

    十七、目录信息(DirectoryInfo)


    一、提要

            本文专门介绍 C# 中的输入和输出。 C# 中的输入和输出基于流。文件流、文件建立修改等属性操作,文件目录操作等。

    二、C# input和output

    2.1 C# 流

            流是字节序列的抽象,例如文件、输入/输出设备、进程间通信管道或 TCP/IP 套接字。流将数据从一个点传输到另一个点。流也能够操纵数据;例如,他们可以压缩或加密数据。在 .NET Framework 中,System.IO 命名空间包含能够读取和写入数据流和文件的类型。

            C# 在 File 类中为 I/O 操作提供高级方法,在 StreamReader 或 StreamWriter 等类中提供低级方法。

    2.2 处理异常(exceptions)

            I/O 操作容易出错。我们可能会遇到异常,例如 FileNotFoundException 或         UnauthorizedAccessException。与 Java 不同,C# 不强制程序员手动处理异常。是否手动处理异常由程序员决定。如果异常没有在 try/catch/finally 结构中手动处理,则由 CLR 处理异常。

    2.3 发行资源(Releasing resources)

            必须释放 I/O 资源。可以使用 Dispose 方法在 finally 子句中手动释放资源。 using 关键字可用于自动释放资源。此外,File 类中的方法会为我们释放资源。

    2.4 文本文件示例

            在示例中,我们使用这个简单的文本文件:

            thermopylae.txt

    The Battle of Thermopylae was fought between an alliance of Greek city-states,
    led by King Leonidas of Sparta, and the Persian Empire of Xerxes I over the
    course of three days, during the second Persian invasion of Greece.ssan

    三、读取整个文件 (File.ReadAllText)

            File 为单个文件的创建、复制、删除、移动和打开提供静态方法,并有助于创建 FileStream 对象。

    Note: The File.ReadAllText is not suited for reading very large files.

            File.ReadAllText 打开一个文件,读取文件中具有指定编码的所有文本,然后关闭文件。

    Program.cs

    1. using System.Text;
    2. var path = "/home/janbodnar/Documents/thermopylae.txt";
    3. var text = File.ReadAllText(path, Encoding.UTF8);
    4. Console.WriteLine(text);

            程序读取thermopylae.txt 文件的内容并将它们打印到控制台。

    var text = File.ReadAllText(path, Encoding.UTF8);
    

            我们一口气将整个文件读入一个字符串。在第二个参数中,我们指定编码。

    $ dotnet run
    The Battle of Thermopylae was fought between an alliance of Greek city-states,
    led by King Leonidas of Sparta, and the Persian Empire of Xerxes I over the
    course of three days, during the second Persian invasion of Greece.
    

    四、逐行读取文件( File.ReadAllLines)

    4.1 逐行读取

            File.ReadAllLines 打开一个文本文件,将文件的所有行读入一个字符串数组,然后关闭文件。 File.ReadAllLines 是一种在 C# 中读取文件的便捷方法。处理非常大的文件时不应使用它。

    Program.cs

    1. var path = "/home/janbodnar/Documents/thermopylae.txt";
    2. string[] lines = File.ReadAllLines(path);
    3. foreach (string line in lines)
    4. {
    5. Console.WriteLine(line);
    6. }

            该示例将文件中的所有行读取到字符串数组中。我们在 foreach 循环中遍历数组并将每一行打印到控制台。

    4.2 生成逐行文件( create file )

            File.CreateText 创建或打开用于写入 UTF-8 编码文本的文件。如果文件已经存在,则覆盖其内容。

    Program.cs

    1. var path = "/home/janbodnar/Documents/cars.txt";
    2. using var sw = File.CreateText(path);
    3. sw.WriteLine("Hummer");
    4. sw.WriteLine("Skoda");
    5. sw.WriteLine("BMW");
    6. sw.WriteLine("Volkswagen");
    7. sw.WriteLine("Volvo");

            在示例中,我们创建了一个 cars.txt 文件并将一些汽车名称写入其中。

    using var sw = File.CreateText(path);
    

            CreateText 方法创建或打开一个用于写入 UTF-8 编码文本的文件。它返回一个 StreamWriter 对象。

    sw.WriteLine("Hummer");
    sw.WriteLine("Skoda");
    ...
    

            我们向流中写入两行。

    五、获取文件建立时间、最后写入、最后访问时间

            通过 File 类,我们可以获得文件的创建、最后写入和最后访问时间。 Exists 方法确定指定文件是否存在。

    Program.cs

    1. var path = "cars.txt";
    2. if (File.Exists(path))
    3. {
    4. Console.WriteLine(File.GetCreationTime(path));
    5. Console.WriteLine(File.GetLastWriteTime(path));
    6. Console.WriteLine(File.GetLastAccessTime(path));
    7. }

            如果指定的文件存在,我们确定它的创建、最后写入和最后访问时间。

    if (File.Exists(path))
    

            如果调用者具有所需的权限并且路径包含现有文件的名称,Exists 方法将返回 true;否则,错误。如果 path 为 null、无效路径或长度为零的字符串,此方法也会返回 false。

    Console.WriteLine(File.GetCreationTime(path));
    Console.WriteLine(File.GetLastWriteTime(path));
    Console.WriteLine(File.GetLastAccessTime(path));
    

            我们得到指定文件的创建时间、最后写入时间和最后访问时间。

    $ dotnet run 2/25/2021 11:41:19 AM 2/25/2021 11:41:19 AM 2/25/2021 11:41:27 AM

    六、拷贝文件

            File.Copy 方法将现有文件复制到新文件。它允许覆盖同名文件。

    Program.cs

    1. var srcPath = "/home/janbodnar/Documents/cars.txt";
    2. var destPath = "/home/janbodnar/Documents/cars2.txt";
    3. File.Copy(srcPath, destPath, true);
    4. Console.WriteLine("File copied");

            然后我们将文件的内容复制到另一个文件中。

    var srcPath = "/home/janbodnar/Documents/cars.txt";
    var destPath = "/home/janbodnar/Documents/cars2.txt";
    
    File.Copy(srcPath, destPath, true);
    

            Copy 方法复制文件。第三个参数指定文件是否应该被覆盖,如果它存在的话。

    七、 异常接口(IDisposable interface)

            流实现了 IDisposable 接口。实现此接口的对象必须尽早手动处置。这是通过在 finally 块中调用 Dispose 方法或使用 using 语句来完成的。

    Program.cs

    1. StreamReader? sr = null;
    2. var path = "thermopylae.txt";
    3. try
    4. {
    5. sr = new StreamReader(path);
    6. Console.WriteLine(sr.ReadToEnd());
    7. }
    8. catch (IOException e)
    9. {
    10. Console.WriteLine("Cannot read file");
    11. Console.WriteLine(e.Message);
    12. }
    13. catch (UnauthorizedAccessException e)
    14. {
    15. Console.WriteLine("Cannot access file");
    16. Console.WriteLine(e.Message);
    17. }
    18. finally
    19. {
    20. sr?.Dispose();
    21. }

            在此示例中,我们从磁盘上的文件中读取字符。我们手动释放分配的资源。

    1. sr = new StreamReader(path);
    2. Console.WriteLine(sr.ReadToEnd());

            StreamReader 类用于读取字符。它的父级实现了 IDisposable 接口。

    1. } catch (IOException e)
    2. {
    3. Console.WriteLine("Cannot read file");
    4. Console.WriteLine(e.Message);
    5. } catch (UnauthorizedAccessException e)
    6. {
    7. Console.WriteLine("Cannot access file");
    8. Console.WriteLine(e.Message);
    9. }

            可能的异常在 catch 块中处理。

    finally
    {
        sr?.Dispose();
    }
    

            在 finally 块中,Dispose 方法清理资源。使用空条件运算符,我们仅在变量不为空时才调用该方法。

    八、用using 定义语句

            using 语句定义了一个范围,对象将在该范围结束。它提供了一种方便的语法,可确保正确使用 IDisposable 对象。

    Program.cs

    var path = "/home/janbodnar/Documents/thermopylae.txt";
    
    using (var sr = new StreamReader(path))
    {
        Console.WriteLine(sr.ReadToEnd());
    }
    

            该示例读取thermopylae.txt 文件的内容。使用 using 语句释放资源。如果我们不处理 IO 异常,它们将由 CLR 处理。

    九、using 声明

            using 声明是一个变量声明,前面有 using 关键字。它告诉编译器被声明的变量应该放在封闭范围的末尾。 using 声明自 C# 8.0 起可用。

    Program.cs

    1. var path = "thermopylae.txt";
    2. using var sr = new StreamReader(path);
    3. Console.WriteLine(sr.ReadToEnd());

            该示例读取thermopylae.txt 文件的内容。当 sr 变量超出范围时(在 Main 方法结束时),资源会自动清理。

    十、内存流MemoryStream

            MemoryStream 是一种处理计算机内存中数据的流。

    Program.cs

    1. using var ms = new MemoryStream(6);
    2. ms.WriteByte(9);
    3. ms.WriteByte(11);
    4. ms.WriteByte(6);
    5. ms.WriteByte(8);
    6. ms.WriteByte(3);
    7. ms.WriteByte(7);
    8. ms.Position = 0;
    9. int rs = ms.ReadByte();
    10. do
    11. {
    12.     Console.WriteLine(rs);
    13.     rs = ms.ReadByte();
    14. } while (rs != -1);

            我们使用 MemoryStream 将六个数字写入内存。然后我们读取这些数字并将它们打印到控制台。

    using var ms = new MemoryStream(6);
    

            该行创建并初始化了一个容量为 6 个字节的 MemoryStream 对象。

    ms.WriteByte(9);
    ms.WriteByte(11);
    ms.WriteByte(6);
    ...
    

            WriteByte 方法在当前位置将一个字节写入当前流。

    ms.Position = 0;
    

            我们使用 Position 属性将光标在流中的位置设置为开头。

    1. do
    2. {
    3. Console.WriteLine(rs);
    4. rs = ms.ReadByte();
    5. } while (rs != -1);

            在这里,我们从流中读取所有字节并将它们打印到控制台。

    $ dotnet run
    9
    11
    6
    8
    3
    7s

    十一、读取流( StreamReader)

            StreamReader 从字节流中读取字符。它默认为 UTF-8 编码。

    Program.cs

    1. var path = "/home/janbodnar/Documents/thermopylae.txt";
    2. using var sr = new StreamReader(path);
    3. while (sr.Peek() >= 0)
    4. {
    5. Console.WriteLine(sr.ReadLine());
    6. }

            我们读取文件的内容。这次我们使用 ReadLine 方法逐行读取文件。

    while (sr.Peek() >= 0)
    {
        Console.WriteLine(sr.ReadLine());
    }
    

            Peek 方法返回下一个可用字符,但不使用它。它指示我们是否可以再次调用 ReadLine 方法。如果没有要读取的字符,则返回 -1。

    十二、行统计(count lines)

            在下一个示例中,我们将计算行数。

    Program.cs

    int count = 0;
    var path = "/home/janbodnar/Documents/thermopylae.txt";
    
    using var sr = new StreamReader(path);
    
    while (sr.ReadLine() != null)
    {
        count++;
    }
    
    Console.WriteLine($"There are {count} lines");
    

    We use a StreamReader and a while loop.

    while(stream.ReadLine() != null)
    {
        count++;
    }
    

            在 while 循环中,我们使用 ReadLine 方法从流中读取一行。它从流中返回一行,如果到达输入流的末尾,则返回 null。

    $ dotnet run
    There are 3 linessshi

    十三、流写入( StreamWriter)

            StreamWriter 以特定编码将字符写入流。

    Program.cs

    var path = "/home/janbodnar/Documents/newfile.txt";
    using var sw = new StreamWriter(path);
    
    sw.WriteLine("Today is a beautiful day.");
    

            该示例使用 StreamWriter 将字符串写入文件。

    using var sw = new StreamWriter(path);
    

            我们创建了一个新的 StreamWriter。默认编码为 UTF-8。 StreamWriter 将路径作为参数。如果文件存在,则覆盖;否则,将创建一个新文件。

    十四、文件流(FileStream)

            FileStream 为文件提供流,支持同步和异步读写操作。StreamReader 和 StreamWriter 处理文本数据,而 FileStream 处理字节。

    Program.cs

    1. using System.Text;
    2. var path = "/home/janbodnar/Documents/newfile2.txt";
    3. using var fs = new FileStream(path, FileMode.Append);
    4. var text = "Фёдор Михайлович Достоевский\n";
    5. byte[] bytes = new UTF8Encoding().GetBytes(text);
    6. fs.Write(bytes, 0, bytes.Length);

            我们将一些俄语西里尔文文本写入文件。

    using .Text;
    

            UTF8Encoding 类位于 System.Text 命名空间中。

    using var fs = new FileStream(path, FileMode.Append);
    

            一个 FileStream 对象被创建。第二个参数是打开文件的模式。如果文件存在,追加模式将打开文件并查找文件末尾,或创建一个新文件。

    var text = "Фёдор Михайлович Достоевский";
    

            这是俄语西里尔文文本。

    byte[] bytes = new UTF8Encoding().GetBytes(text);
    

            从俄语西里尔文文本创建一个字节数组。

    fs.Write(bytes, 0, bytes.Length);
    

            我们将字节写入文件流。

    $ cat /home/janbodnar/Documents/newfile2.txt
    Фёдор Михайлович Достоевский
    

            我们显示创建的文件的内容。

    十五、xml文件读取(XmlTextReader)

            我们可以使用流来读取 XML 数据。 XmlTextReader 是在 C# 中读取 XML 文件的类。该类是只进的和只读的。

            我们有以下 XML 测试文件:

    languages.xml

    1. "1.0" encoding="utf-8" ?>
    2. Python
    3. Ruby
    4. Javascript
    5. C#

            此文件包含自定义 XML 标记之间的语言名称。

    Program.cs

    1. using System.Xml;
    2. string path = "/home/janbodnar/Documents/languages.xml";
    3. using var xreader = new XmlTextReader(path);
    4. xreader.MoveToContent();
    5. while (xreader.Read())
    6. {
    7. var node = xreader.NodeType switch
    8. {
    9. XmlNodeType.Element => String.Format("{0}: ", xreader.Name),
    10. XmlNodeType.Text => String.Format("{0} \n", xreader.Value),
    11. _ => ""
    12. };
    13. Console.Write(node);
    14. }

            此示例从 XML 文件中读取数据并将其打印到终端。

    using System.Xml;
    

            System.Xml 命名空间包含与 Xml 读写相关的类。

    using var xreader = new XmlTextReader(path);
    

            创建一个 XmlTextReader 对象。它是一种提供对 XML 数据的快速、非缓存、只进的访问的阅读器。它将文件名作为参数。

            xreader.MoveToContent();


            MoveToContent 方法移动到 XML 文件的实际内容。

            while (xreader.Read())

            此行从流中读取下一个节点。如果没有更多节点,Read 方法将返回 false。

    var node = xreader.NodeType switch
    {
        XmlNodeType.Element => String.Format("{0}: ", xreader.Name),
        XmlNodeType.Text => String.Format("{0} \n", xreader.Value),
        _ => ""
    };
    
    Console.Write(node);
    

            这里我们打印元素名称和元素文本。

    $ dotnet run
    language: Python
    language: Ruby
    language: Javascript
    language: C#
    

    十六、生成和转移create, move directory

            System.IO.Directory 是一个类,它具有用于创建、移动和枚举目录和子目录的静态方法。

    Program.cs

    Directory.CreateDirectory("temp");
    Directory.CreateDirectory("newdir");
    Directory.Move("temp", "temporary");
    

            我们创建两个目录并重命名创建的目录之一。目录是在项目文件夹中创建的。

    Directory.CreateDirectory("temp");
    
    CreateDirectory 方法创建一个新目录。
    Directory.Move("temp", "temporary");
    
    Move 方法为指定的目录提供了一个新名称。
    

    十七、目录信息(DirectoryInfo)

            DirectoryInfo 公开了用于创建、移动和枚举目录和子目录的实例方法。

    Program.cs

    1. var path = "/home/janbodnar/Documents";
    2. var dirInfo = new DirectoryInfo(path);
    3. string[] files = Directory.GetFiles(path);
    4. DirectoryInfo[] dirs = dirInfo.GetDirectories();
    5. foreach (DirectoryInfo subDir in dirs)
    6. {
    7. Console.WriteLine(subDir.Name);
    8. }
    9. foreach (string fileName in files)
    10. {
    11. Console.WriteLine(fileName);
    12. }

            我们使用 DirectoryInfo 类遍历特定目录并打印其内容。

    var path = "/home/janbodnar/Documents";
    var DirInfo = new DirectoryInfo(path);
    

            我们显示指定目录的内容。

    string[] files = Directory.GetFiles(path);
    

            我们使用静态 GetFiles 方法获取目录的所有文件。

    DirectoryInfo[] dirs = dir.GetDirectories();
    

            我们得到所有的目录。

    foreach (DirectoryInfo subDir in dirs)
    {
        Console.WriteLine(subDir.Name);
    }
    

            在这里,我们遍历目录并将它们的名称打印到控制台。

    foreach (string fileName in files)
    {
        Console.WriteLine(fileName);
    }
    

            在这里,我们遍历文件数组并将它们的名称打印到控制台。

            在本章中,我们介绍了 C# 中的输入/输出操作。

  • 相关阅读:
    Web前端vueDemo—实现天气预报功能(四)
    C#中的日期时间比较和格式化的方法
    爬虫 — Js 逆向案例五闪职网登录
    计算机网络4小时速成:计算机网络基础,计网组成,计网分类,性能指标,标准化组织,计网结构模型,五层模型
    【华为OD机试python】数字涂色【2023 B卷|100分】
    后勤仓库物资领用发放小程序开发制作功能介绍
    198. 打家劫舍
    新店速递丨白玉兰(商务)酒店赣榆吾悦广场店 正式上线
    比较各JAX-RS实现:Jersey,Restlet,CXF,RESTEasy
    [HQS]C++相关语法
  • 原文地址:https://blog.csdn.net/gongdiwudu/article/details/123445999