简体   繁体   English

C#异步Zip文件提取

[英]C# Async Zip File Extraction

I've done some looking, but haven't found much in the way of example async methods that are not either incredibly complex or very simple. 我已经做了一些查找,但是在示例异步方法方面并没有发现太多东西,这些方法既不是非常复杂也不是非常简单。

I've been trying to make an application more efficient, and am convinced I don't need to implement my own threading. 我一直在尝试使应用程序更高效,并且确信我不需要实现自己的线程。 Basically this code is from an application that already has functioning async calls that use Cookie Aware Web Client code to log into an HTTPS site, grab the cookie, enumerate a specific page with the authentication cookie and then download specific files. 基本上,此代码来自已经具有功能正常的异步调用的应用程序,该应用程序使用Cookie Aware Web客户端代码登录到HTTPS站点,获取cookie,使用身份验证cookie枚举特定页面,然后下载特定文件。 Said specific files are "zip" format with extension ".bfp". 所述特定文件是扩展名为“ .bfp”的“ zip”格式。 This section of code below is used to extract the zip files (there are tens of thousands of them from over 100 source IPs being downloaded into a folder structure). 下面的代码部分用于提取zip文件(从100多个源IP中下载了成千上万个ip文件到一个文件夹结构中)。

My problem is that the application freezes part way through parsing the files using this async setup, but once in a while will finish. 我的问题是,应用程序使用此异步设置解析文件时会冻结一部分,但是偶尔会完成。 Sometimes it hangs and just sits there, other times it crashes and Windows Error Reporting pops up. 有时它会挂起并坐在那儿,有时它会崩溃并弹出Windows错误报告。

As a note, I have a BS CIS degree, but I am not a programmer in my day to day job. 注意,我拥有BS CIS学位,但是我不是日常工作的程序员。 I am a systems engineer/architect (I have a BS and MS in that as well). 我是系统工程师/架构师(我也有BS和MS)。 I have no one here to bounce my code off that has any programming experience. 我没有人在这里弹奏过我的代码,因为我有任何编程经验。 What I know about the async/await libraries I've learned from Channel9 videos from MS and Google. 我从MS和Google的Channel9视频中学到的关于异步/等待库的知识。 If this implementation looks terrible, it could be, and I do NOT claim to be an expert, especially with async. 如果此实现看起来很糟糕,那就可能是这样,而且我也不会声称自己是专家,特别是使用异步时。 I am leaving out most of the code for the other parts of the app that are running fine, as it has information I would prefer not to share and it is not relevant to the question/problem. 我为应用程序的其他部分省去了大部分运行良好的代码,因为它具有我不希望共享的信息,并且与问题/问题无关。

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);
    }
}

I have used Task.WhenAll() before, and I think you want to simplify any line with that in it. 我之前使用过Task.WhenAll(),我想您想简化其中的任何一行。 You have way more await statements than you need, and Task.Run will start in a new thread. 您有更多的等待语句,而Task.Run将在新线程中启动。 It's likely you are creating conditions where nothing is finishing because of the way you've structured the await statements. 由于您构造了await语句的方式,很可能您正在创建无法完成的条件。 So why not have one thread per zip? 那么,为什么每个拉链都没有一个线程呢?

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)));
     }
}
)));
}

Also, change this line of code 另外,更改此行代码

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

Not ultimately sure if that line was meant to call ParseZipFile() instead of ParseLogFile() but you have the code and I don't. 最终不确定该行是否要调用ParseZipFile()而不是ParseLogFile(),但是您有代码,但我没有。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM