异步读/写多个文件
本文关键字:文件 异步 | 更新日期: 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);