【问题标题】:Does the .net framework provides async methods for working with the file-system?.net 框架是否提供用于处理文件系统的异步方法?
【发布时间】:2016-06-15 11:58:22
【问题描述】:

.net 框架是否有一个async 内置库/程序集允许使用文件系统(例如File.ReadAllBytes、File.WriteAllBytes)?

还是我必须使用StreamReader 和StreamWriter 的async 方法编写自己的库?

这样的东西会很不错:

var bytes = await File.ReadAllBytes("my-file.whatever");

【问题讨论】:

    标签: c# asynchronous filesystems async-await system.io.file


    【解决方案1】:

    不,但您可以使用 FileStream 创建相同的行为。

    这是我为 NetStandart 2.0 class library 创建的辅助方法,在 NetCore 3.1 和 NetFramework 4.7.2 项目中都使用过。

    这些实现与net core 3.1 / net standard 2.1 File类方法的名称和签名完全匹配,因此您只需将它们放在任何公共类中即可。 (例如 FileHelper...):

    另外,这应该是最有效的,并且类似于 .net 实现的源代码。

    private const int DefaultBufferSize = 4096;
    
        // File accessed asynchronous reading and sequentially from beginning to end.
        private const FileOptions DefaultOptions = FileOptions.Asynchronous | FileOptions.SequentialScan;
    
        public static async Task WriteAllTextAsync(string filePath, string text)
        {
            byte[] encodedText = Encoding.Unicode.GetBytes(text);
    
            using FileStream sourceStream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None,
                DefaultBufferSize, true);
            await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
        }
    
        public static async Task<IEnumerable<string>> ReadAllLinesAsync(string filePath)
        {
            var lines = new List<string>();
    
            using var sourceStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read,
                DefaultBufferSize, DefaultOptions);
            using var reader = new StreamReader(sourceStream, Encoding.Unicode);
            string line;
            while ((line = await reader.ReadLineAsync()) != null) lines.Add(line);
    
            return lines;
        }
    
        public static async Task<string> ReadAllTextAsync(string filePath)
        {
            using var sourceStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read,
                DefaultBufferSize, DefaultOptions);
            using var reader = new StreamReader(sourceStream, Encoding.Unicode);
            return await reader.ReadToEndAsync();
        }
    

    【讨论】:

      【解决方案2】:

      在 .NET 核心(自 2.0 版起)中,现在有相应 ReadAll/WriteAll/AppendAll 方法的所有异步风格,例如:

      File.(Read|Write|Append)All(Text|Lines|Bytes)Async
      

      https://docs.microsoft.com/en-us/dotnet/api/system.io.file.readallbytesasync?view=netcore-2.1

      不幸的是,.NET 标准 2.0 中仍然缺少它们。

      【讨论】:

      【解决方案3】:

      .net 框架是否有一个异步内置库/程序集允许使用文件系统(例如 File.ReadAllBytes、File.WriteAllBytes)?

      不幸的是,当涉及到异步文件操作时,桌面 API 有点参差不齐。正如您所指出的,许多不错的便捷方法没有异步等效方法。还缺少文件的异步打开(这在通过网络共享打开文件时特别有用)。

      我希望随着世界转向 .NET Core,这些 API 将被添加。

      还是我必须使用 StreamReader 和 StreamWriter 的异步方法编写自己的库?

      这是目前最好的方法。

      请注意,当使用ReadAsync/WriteAsync 和朋友时,您必须显式打开文件以进行异步访问。这样做的唯一方法(当前)是使用FileStream 构造函数重载,它采用bool isAsync 参数(传递true)或FileOptions 参数(传递FileOptions.Asynchronous)。所以你不能使用像File.Open这样的便捷打开方法。

      【讨论】:

      • 感谢您提供这些信息,尤其是:FileOptions.Asynchronous 谢谢! isAsync 似乎被贬低了。 +1
      • @BendEg 如果您在一堆constructor overloads for FileStream 附近看到弃用警告,那么这些过时的警告似乎是IntPtr 的FileStream() 变体,因为SafeHandle 替代方案更好/更安全。您可以看到,例如,this filename overload with useAsync 没有标记为作废。
      【解决方案4】:

      .net 框架是否有一个异步内置库/程序集,允许使用文件系统

      是的。有用于处理文件系统的异步方法,但没有用于静态 File 类型的辅助方法。他们在FileStream。

      所以,没有File.ReadAllBytesAsync,但有FileStream.ReadAsync,等等。例如:

      byte[] result;
      using (FileStream stream = File.Open(@"C:\file.txt", FileMode.Open))
      {
          result = new byte[stream.Length];
          await stream.ReadAsync(result, 0, (int)stream.Length);
      }
      

      【讨论】:

      • 如果您要序列化为字节流的文件很大(3gb+),流长度是否有可能实际上大于 int 类型可以存储并导致溢出?
      • @Dave 可能。在这种情况下,您可能需要分块阅读。
      • 无论如何,您都应该有逻辑来读取块。根据Microsoft documentation,不能保证 ReadAsync 填满整个数组。您需要检查返回值以查看它实际读取了多少。
      • 您可以考虑将代码更改为something like this(对于小文件 - 不要对 3 GB 以上的文件这样做)。
      • 你真的应该使用System.IO.StreamReader 来读取而不是抓取原始字节。它有ReadLineAsync 和ReadToEndAsync 方法。
      【解决方案5】:

      它已经做到了。参见例如Using Async for File Access MSDN 文章。

      private async Task WriteTextAsync(string filePath, string text)
      {
          byte[] encodedText = Encoding.Unicode.GetBytes(text);
      
          using (FileStream sourceStream = new FileStream(filePath,
              FileMode.Append, FileAccess.Write, FileShare.None,
              bufferSize: 4096, useAsync: true))
          {
              await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
          };
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多