使用C#以同步方式下载文件并异步提取下载的文件
Download files in synchronous manner and extract downloaded files asynchronously using C#
我有一些大型 zip 文件的 URL 列表。我正在使用 HttpClient
循环下载文件。我必须在下载过程后解压缩文件。我想在每个文件完成下载时开始解压,而不是等待整个下载过程完成。文件下载应该以同步方式(一个接一个)进行,提取应该与每个下载的文件异步进行。我的应用程序正在使用 .Net Framework 4.5.2 和 C#7。
在下面的代码中,文件下载也是异步的。由于带宽问题,我试图避免异步下载。
public void DownloadAndExtract()
{
IDataReader dr = _myDB.GetFileUrl();
while (dr.Read())
{
DownloadFile(new Uri(dr["URL"].ToString())).ContinueWith(task1 =>
{
var downloadedFilePath = task1.Result.fileName;
ExtractFile(downloadedFilePath).GetAwaiter().GetResult();
});
}
dr.Close();
}
我想我会简化我的生活:
public async Task DownloadAndExtractAsync()
{
using(IDataReader dr = _myDB.GetFileUrl()){
while (dr.Read())
{
var f = await DownloadFileAsync(new Uri(dr["URL"].ToString()));
_ = ExtractFileAsync(f.fileName);
}
}
}
对此唯一让我感到不安的是,它可能会使数据库连接保持打开状态的时间过长。也许:
public async Task DownloadAndExtractAsync()
{
DataTable dt = new DataTable();
using(IDataReader dr = _myDB.GetFileUrl())
dt.Load(dr);
foreach(DataRow dr in dt.Rows)
{
var f = await DownloadFileAsync(new Uri(dr["URL"].ToString()));
_ = ExtractFileAsync(f.fileName);
}
}
后缀(使用 ...Async
)以异步方式运行的方法将使必须阅读代码的人受益,尤其是互联网上无法受益于 intellisense/definition 的人你调用的方法
这里有一个TPL Dataflow implementation. Two blocks are used, one TransformBlock<Uri, string>
for downloading the URLs, and one ActionBlock<string>
用于提取文件。
private void DownloadAndExtract()
{
var downloadBlock = new TransformBlock<Uri, string>(async uri =>
{
var downloadedFile = await DownloadFileAsync(uri);
return downloadedFile.fileName;
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 1
});
var extractBlock = new ActionBlock<string>(async filePath =>
{
await ExtractFileAsync(filePath);
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
});
downloadBlock.LinkTo(extractBlock,
new DataflowLinkOptions() { PropagateCompletion = true });
IDataReader dr = _myDB.GetFileUrl();
while (dr.Read())
{
downloadBlock.Post(new Uri(dr["URL"].ToString()));
}
dr.Close();
downloadBlock.Complete();
extractBlock.Completion.Wait();
}
在将所有 Uri
发布到 downloadBlock
之前将它们存储在列表中会更安全。使用上面的代码,数据库中一个格式错误的 URL
将导致 DownloadAndExtract
方法失败,而以前的 URL 将在后台下载和提取,以一种即刻即忘的方式。
注意:我在异步方法DownloadFile
和ExtractFile
后面加了Async
后缀,以符合guidelines.
我有一些大型 zip 文件的 URL 列表。我正在使用 HttpClient
循环下载文件。我必须在下载过程后解压缩文件。我想在每个文件完成下载时开始解压,而不是等待整个下载过程完成。文件下载应该以同步方式(一个接一个)进行,提取应该与每个下载的文件异步进行。我的应用程序正在使用 .Net Framework 4.5.2 和 C#7。
在下面的代码中,文件下载也是异步的。由于带宽问题,我试图避免异步下载。
public void DownloadAndExtract()
{
IDataReader dr = _myDB.GetFileUrl();
while (dr.Read())
{
DownloadFile(new Uri(dr["URL"].ToString())).ContinueWith(task1 =>
{
var downloadedFilePath = task1.Result.fileName;
ExtractFile(downloadedFilePath).GetAwaiter().GetResult();
});
}
dr.Close();
}
我想我会简化我的生活:
public async Task DownloadAndExtractAsync()
{
using(IDataReader dr = _myDB.GetFileUrl()){
while (dr.Read())
{
var f = await DownloadFileAsync(new Uri(dr["URL"].ToString()));
_ = ExtractFileAsync(f.fileName);
}
}
}
对此唯一让我感到不安的是,它可能会使数据库连接保持打开状态的时间过长。也许:
public async Task DownloadAndExtractAsync()
{
DataTable dt = new DataTable();
using(IDataReader dr = _myDB.GetFileUrl())
dt.Load(dr);
foreach(DataRow dr in dt.Rows)
{
var f = await DownloadFileAsync(new Uri(dr["URL"].ToString()));
_ = ExtractFileAsync(f.fileName);
}
}
后缀(使用 ...Async
)以异步方式运行的方法将使必须阅读代码的人受益,尤其是互联网上无法受益于 intellisense/definition 的人你调用的方法
这里有一个TPL Dataflow implementation. Two blocks are used, one TransformBlock<Uri, string>
for downloading the URLs, and one ActionBlock<string>
用于提取文件。
private void DownloadAndExtract()
{
var downloadBlock = new TransformBlock<Uri, string>(async uri =>
{
var downloadedFile = await DownloadFileAsync(uri);
return downloadedFile.fileName;
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 1
});
var extractBlock = new ActionBlock<string>(async filePath =>
{
await ExtractFileAsync(filePath);
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
});
downloadBlock.LinkTo(extractBlock,
new DataflowLinkOptions() { PropagateCompletion = true });
IDataReader dr = _myDB.GetFileUrl();
while (dr.Read())
{
downloadBlock.Post(new Uri(dr["URL"].ToString()));
}
dr.Close();
downloadBlock.Complete();
extractBlock.Completion.Wait();
}
在将所有 Uri
发布到 downloadBlock
之前将它们存储在列表中会更安全。使用上面的代码,数据库中一个格式错误的 URL
将导致 DownloadAndExtract
方法失败,而以前的 URL 将在后台下载和提取,以一种即刻即忘的方式。
注意:我在异步方法DownloadFile
和ExtractFile
后面加了Async
后缀,以符合guidelines.