异步读/写多个文件

本文关键字:文件 异步 | 更新日期: 2023-09-27 17:56:53

我们正在构建一个自定义CMS,其中我们必须通过我的管理面板一次性覆盖服务器上多个HTML文件(约1000个)的内容。我是异步和并行编程的新手,所以经过一些研发,我决定使用并行编程(TPL)来解决我的问题,下面是我用来用一些文本覆盖文件的示例代码。

现在的问题是我也必须并行读取多个文件,在我的示例中,我使用了一个简单的变量字符串文本 = "In file" + index。ToString(),但实际上每个被覆盖的文件都将被数据库中的静态模板(对于每个页面)和一些动态值(对于CMS元素)所取代。我不明白如何并行对多个文件进行多次读/写:

    static async void ProcessWriteMultAsync()
    {
        string folder = @"E:'test'";
        string[] items = { "Site1", "Site2", "Site3", "Site4", "Site5", "Site6", "Site7", "Site8", "Site9", "Site10", "Site11", "Site12", "Site13", "Site14",
        "Site15","Site16","Site17","Site18","Site19","Site20",};
        List<Task> tasks = new List<Task>();
        List<FileStream> sourceStreams = new List<FileStream>();
        try
        {
            for (int index = 0; index < items.Length; index++)
            {
                string text = "In file " + index.ToString();
                string filePath = folder + items[index] + "''ProcurementTemplate.html";
                byte[] encodedText = Encoding.Unicode.GetBytes(text);
                FileStream sourceStream = new FileStream(filePath,
                    FileMode.Create, FileAccess.Write, FileShare.None,
                    bufferSize: 4096, useAsync: true);
                Task theTask = sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
                sourceStreams.Add(sourceStream);
                tasks.Add(theTask);
            }
            await Task.WhenAll(tasks);
        }
        finally
        {
            foreach (FileStream sourceStream in sourceStreams)
            {
                sourceStream.Close();
            }
        }
    } 

异步读/写多个文件

首先,拉取逻辑以将文件写入方法:

async Task Write(string text, string filePath) {
                byte[] encodedText = Encoding.Unicode.GetBytes(text);
                using (FileStream sourceStream = new FileStream(filePath)) {
                await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
 }
}

然后使用 Stephen Toubs ForEachAsync 处理所有项目。您需要通过实验确定正确的并行度。它肯定不会像现在在您的代码中那样是 1000。正确的 DOP 取决于 IO 系统和操作系统缓冲的数据量。

items.ForEachAsync(async (item) => await Write(item, GetPath(...)), dop: 8);

旧代码基本上有效,但它的级别很低且冗长。

您可以创建一个任务数组 - 每个文件一个 - 然后使用Task.WaitAll运行它们:

public async Task DoWorkAsync(string text, string file)
{
    using(FileStream sourceStream = new FileStream(file, FileMode.Create, FileAccess.Write))
    {
        byte[] encodedText = Encoding.Unicode.GetBytes(text);
        await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
    }
}
IEnumerable<string> fileNames = new string[] { "file1.txt", "file2.txt" };
Task[] writingTasks = fileNames
                          .Select(fileName => DoWorkAsync("some text", fileName))
                          .ToArray();
await Task.WhenAll(writingTasks);