C#异步Zip文件提取

时间:2017-09-07 18:08:26

标签: c# asynchronous async-await zip zipfile

我已经完成了一些工作,但是在示例异步方法方面没有找到太多方法,这些异步方法既不复杂也不简单。

我一直在努力提高应用程序的效率,并且我确信我不需要实现自己的线程。基本上,此代码来自已经具有异步调用的应用程序,该异步调用使用Cookie Aware Web客户端代码登录到HTTPS站点,获取cookie,使用身份验证cookie枚举特定页面,然后下载特定文件。所述特定文件是“zip”格式,扩展名为“.bfp”。下面这段代码用于提取zip文件(从100多个源IP中下载到文件夹结构中的数万个)。

我的问题是应用程序通过使用此异步设置解析文件的一部分冻结,但偶尔会完成。有时它会挂起并且只是坐在那里,有时它会崩溃并弹出Windows错误报告。

作为一个说明,我有一个BS CIS学位,但我不是一个日常工作的程序员。我是系统工程师/架构师(我也有BS和MS)。我没有人在这里反弹任何有任何编程经验的代码。我对从MS和Google的Channel9视频中学到的async / await库的了解。如果这个实现看起来很糟糕,它可能是,而且我并不声称自己是专家,尤其是异步。我遗漏了应用程序运行正常的其他部分的大部分代码,因为它有我不想分享的信息,而且与问题/问题无关。

private async void ParseZipFiles()
{

    await UpdateMain("Started Parsing Compressed Log Files." + Environment.NewLine);
    FileInfo[] diZip = new DirectoryInfo(@"C:\LogFiles\ZipFiles\").GetFiles("*.bfp",SearchOption.AllDirectories);
    await Task.WhenAll(diZip.Select(async s => await Task.Run(async () => await ParseLogFile(s.FullName))));
    await UpdateMain("Finished Parsing Compressed Log Files." + Environment.NewLine);
}

private async Task ParseZipFile(string filename)
{
    try
    {
        using (ZipArchive bfpFile = await Task.Run(async () => new ZipArchive((Stream)new FileStream(filename, FileMode.Open))))
        {
            await Task.WhenAll(bfpFile.Entries.Select(async s => await Task.Run(async () =>
            {
               if (s.FullName.EndsWith(".log", StringComparison.OrdinalIgnoreCase) && s.Name.Split('.').First().All(char.IsDigit) == true && s.Name.Split('.').Count() == 2)
                {
                    string extractPath = Path.Combine(@"C:\LogFiles\Extracted\" + filename.Split('\\')[3].ToString() + @"\", s.Name);
                    await Task.Run(async () => await Task.Run(() =>  s.ExtractToFile(extractPath, true)));
                }
            })));
        }
    }
    catch
    {
        await UpdateMain("Compressed archive: " + filename + " is corrupted. Probably on the source system." + Environment.NewLine);
    }
}

1 个答案:

答案 0 :(得分:0)

之前我使用过Task.WhenAll(),我想你想用它来简化任何一行。你有更多的等待语句,而Task.Run将在一个新的线程中启动。由于您构建await语句的方式,您可能正在创建无法完成任务的条件。那么为什么每个拉链都没有一个线程?

using (ZipArchive bfpFile = new ZipArchive(new FileStream(filename, 
FileMode.Open))) {
await Task.WhenAll(bfpFile.Entries.Select(s => Task.Run(() =>
{
    if (s.FullName.EndsWith(".log", StringComparison.OrdinalIgnoreCase) && s.Name.Split('.').First().All(char.IsDigit) == true && s.Name.Split('.').Count() == 2)
    {
         string extractPath = Path.Combine(@"C:\LogFiles\Extracted\" + filename.Split('\\')[3].ToString() + @"\", s.Name);
         s.ExtractToFile(extractPath, true)));
     }
}
)));
}

另外,更改此行代码

await Task.WhenAll(diZip.Select(s => Task.Run(() => 
ParseLogFile(s.FullName))));

最终不确定该行是否意味着调用ParseZipFile()而不是ParseLogFile(),但是你有代码而我没有。