当前位置: 首页 > article >正文

windows C#-异步文件访问

可使用异步功能访问文件。 通过使用异步功能,你可以调用异步方法而无需使用回调,也不需要跨多个方法或 lambda 表达式来拆分代码。 若要使同步代码异步,只需调用异步方法而非同步方法,并向代码中添加几个关键字。

可能出于以下原因向文件访问调用中添加异步:

  • 异步使 UI 应用程序响应速度更快,因为启动该操作的 UI 线程可以执行其他操作。 如果 UI 线程必须执行耗时较长的代码(例如超过 50 毫秒),UI 可能会冻结,直到 I/O 完成,此时 UI 线程可以再次处理键盘和鼠标输入及其他事件;
  • 异步可减少对线程的需要,进而提高 ASP.NET 和其他基于服务器的应用程序的可伸缩性。 如果应用程序对每次响应都使用专用线程,同时处理 1000 个请求时,则需要 1000 个线程。 异步操作在等待期间通常不需要使用线程。 异步操作仅需在结束时短暂使用现有 I/O 完成线程;
  • 当前条件下,文件访问操作的延迟可能非常低,但以后可能大幅增加。 例如,文件可能会移动到覆盖全球的服务器;
  • 使用异步功能所增加的开销很小;
  • 异步任务可以轻松地并行运行;
使用适当的类

后续的简单示例演示 File.WriteAllTextAsync 和 File.ReadAllTextAsync。 要对文件 I/O 操作进行精细的控制,请使用 FileStream 类,该类有一个可导致在操作系统级别出现异步 I/O 的选项。 使用此选项可避免在许多情况下阻止线程池线程。 若要启用此选项,可在构造函数调用中指定 useAsync=true 或 options=FileOptions.Asynchronous 参数。

如果通过指定文件路径直接打开 StreamReader 和 StreamWriter,则无法将此选项与这二者配合使用。 但是,如果为二者提供已由 FileStream 类打开的 Stream,则可以使用此选项。 即使线程池线程受到阻止,UI 应用中的异步调用也会更快,因为 UI 线程在等待期间不会受到阻止。

写入文本

下面的示例将文本写入文件。 在每个 await 语句中,该方法会立即退出。 文件 I/O 完成后,该方法将在 await 语句后面的语句中继续。 Async 修饰符位于使用 await 语句的方法定义中。

public async Task SimpleWriteAsync()
{
    string filePath = "simple.txt";
    string text = $"Hello World";

    await File.WriteAllTextAsync(filePath, text);
}
有限控制示例 
public async Task ProcessWriteAsync()
{
    string filePath = "temp.txt";
    string text = $"Hello World{Environment.NewLine}";

    await WriteTextAsync(filePath, text);
}

async Task WriteTextAsync(string filePath, string text)
{
    byte[] encodedText = Encoding.Unicode.GetBytes(text);

    using var sourceStream =
        new FileStream(
            filePath,
            FileMode.Create, FileAccess.Write, FileShare.None,
            bufferSize: 4096, useAsync: true);

    await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
}

原始示例包含 await sourceStream.WriteAsync(encodedText, 0, encodedText.Length); 语句,它是下面两个语句的缩写式:

Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
await theTask;

第一条语句返回任务,并会导致文件处理启动。 具有 await 的第二条语句将使方法立即退出并返回一个不同的任务。 文件处理稍后完成后,执行将返回到 await 后面的语句中。

读取文本

下面的示例从文件中读取文本。

public async Task SimpleReadAsync()
{
    string filePath = "simple.txt";
    string text = await File.ReadAllTextAsync(filePath);

    Console.WriteLine(text);
}
有限控制示例

将会缓冲文本,并且在此情况下,会将其放入 StringBuilder。 与前一示例不同,await 的计算将生成一个值。 ReadAsync 方法返回 Task<Int32>,因此在操作完成后 await 的评估会得出 Int32 值 numRead。

public async Task ProcessReadAsync()
{
    try
    {
        string filePath = "temp.txt";
        if (File.Exists(filePath) != false)
        {
            string text = await ReadTextAsync(filePath);
            Console.WriteLine(text);
        }
        else
        {
            Console.WriteLine($"file not found: {filePath}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

async Task<string> ReadTextAsync(string filePath)
{
    using var sourceStream =
        new FileStream(
            filePath,
            FileMode.Open, FileAccess.Read, FileShare.Read,
            bufferSize: 4096, useAsync: true);

    var sb = new StringBuilder();

    byte[] buffer = new byte[0x1000];
    int numRead;
    while ((numRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
    {
        string text = Encoding.Unicode.GetString(buffer, 0, numRead);
        sb.Append(text);
    }

    return sb.ToString();
}
并行异步 I/O

下面的示例通过编写 10 个文本文件来演示并行处理。

public async Task SimpleParallelWriteAsync()
{
    string folder = Directory.CreateDirectory("tempfolder").Name;
    IList<Task> writeTaskList = new List<Task>();

    for (int index = 11; index <= 20; ++ index)
    {
        string fileName = $"file-{index:00}.txt";
        string filePath = $"{folder}/{fileName}";
        string text = $"In file {index}{Environment.NewLine}";

        writeTaskList.Add(File.WriteAllTextAsync(filePath, text));
    }

    await Task.WhenAll(writeTaskList);
}
有限控制示例

对于每个文件,WriteAsync 方法将返回一个任务,此任务随后将添加到任务列表中。 await Task.WhenAll(tasks); 语句将退出该方法,并在所有任务的文件处理完成时在此方法中继续。

该示例将在任务完成后关闭 finally 块中的所有 FileStream 实例。 如果每个 FileStream 均已在 using 语句中创建,则可能在任务完成前释放 FileStream。

任何性能提升都几乎完全来自并行处理而不是异步处理。 异步的优点在于它不会占用多个线程,也不会占用用户界面线程。

public async Task ProcessMultipleWritesAsync()
{
    IList<FileStream> sourceStreams = new List<FileStream>();

    try
    {
        string folder = Directory.CreateDirectory("tempfolder").Name;
        IList<Task> writeTaskList = new List<Task>();

        for (int index = 1; index <= 10; ++ index)
        {
            string fileName = $"file-{index:00}.txt";
            string filePath = $"{folder}/{fileName}";

            string text = $"In file {index}{Environment.NewLine}";
            byte[] encodedText = Encoding.Unicode.GetBytes(text);

            var sourceStream =
                new FileStream(
                    filePath,
                    FileMode.Create, FileAccess.Write, FileShare.None,
                    bufferSize: 4096, useAsync: true);

            Task writeTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
            sourceStreams.Add(sourceStream);

            writeTaskList.Add(writeTask);
        }

        await Task.WhenAll(writeTaskList);
    }
    finally
    {
        foreach (FileStream sourceStream in sourceStreams)
        {
            sourceStream.Close();
        }
    }
}

当使用 WriteAsync 和 ReadAsync 方法时,可以指定可用于取消操作中间流的 CancellationToken。 


http://www.kler.cn/a/409368.html

相关文章:

  • leetcode-24-两两交换链表中的节点
  • 练习题 - Django 4.x Templates 渲染页面模板使用示例和配置方法
  • 使用 Nginx 在 Ubuntu 22.04 上安装 LibreNMS 开源网络监控系统
  • CLIP-Adapter: Better Vision-Language Models with Feature Adapters 论文解读
  • 实战OpenCV之人脸识别
  • 泛型擦除是什么?
  • python 什么是数据类dataclass,以及它的应用场景
  • 论文阅读--Evidence for the utility of quantum computing before fault tolerance
  • 跟我学OceanBase4.0 --阅读白皮书 (0.5-4.0的架构与之前架构特点)
  • 人工智能之机器学习5-回归算法2【培训机构学习笔记】
  • 【Rabbitmq篇】RabbitMQ⾼级特性----持久性,发送⽅确认,重试机制
  • Kafka 生产者优化与数据处理经验
  • MySQL-学习笔记
  • 【npm设置代理-解决npm网络连接error network失败问题】
  • 算法笔记:前缀和
  • 【Spring Boot】# 使用@Scheduled注解无法执行定时任务
  • SQL Server 2008中配置快照复制
  • 算法日记 32 day 动态规划(完全背包)
  • 部署mediapipe 问题解决
  • Spring AI 框架使用的核心概念
  • 软件项目集成工作流,工作流自定义绘制,流程设计器,审批会签,审批驳回,自定义表单,activiti,springboot,JAVA整合(源代码案例)
  • WebSocket 常见问题及解决方案
  • 二手手机回收小程序,一键便捷高效回收
  • matlab基础例题
  • 【gitlab】部署
  • 【Unity3D编辑器扩展】Unity3D中实现快速切换场景功能(提高效率)