使用进度条提取存档文件?

3
在这种情况下,我该如何使用进度条?
void Client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    //System.Windows.MessageBox.Show("Update Complete!", "Message", MessageBoxButton.OK, MessageBoxImage.Information);
    Uri uri = new Uri(url);
    string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
    ZipFile.ExtractToDirectory(filePathDir + "/" + filename, filePathDir);
}

编辑: @Alessandro D'Andria , 但在这种情况下呢?

WebClient wc = new WebClient();
Stream zipReadingStream = wc.OpenRead(url);
ZipArchive zip = new ZipArchive(zipReadingStream);
ZipFileExtensions.ExtractToDirectory(zip, filePathDir);

1
通过处理 DownloadProgressChanged 事件:https://msdn.microsoft.com/zh-cn/library/system.net.webclient.downloadprogresschanged(v=vs.110).aspx - ThePerplexedOne
2
@ThePerplexedOne:他在询问如何解压缩ZIP文件,而不是使用“WebClient”。 - SLaks
你不能这样做,最好的方法是使用System.IO.Compression中的默认实现手动提取每个文件并跟踪进度。 - Alessandro D'Andria
@Alessandro D'Andria,我如何追踪进度? - user7923477
2个回答

8

您可以在GitHub上查看ExtractToDirectory的代码,您只需要传入一个Progress<ZipProgress>参数,并在 foreach 循环内调用它即可。

//This is a new class that represents a progress object.
public class ZipProgress
{
    public ZipProgress(int total, int processed, string currentItem)
    {
        Total = total;
        Processed = processed;
        CurrentItem = currentItem;
    }
    public int Total { get; }
    public int Processed { get; }
    public string CurrentItem { get; }
}

public static class MyZipFileExtensions
{
    public static void ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, IProgress<ZipProgress> progress)
    {
        ExtractToDirectory(source, destinationDirectoryName, progress, overwrite: false);
    }

    public static void ExtractToDirectory(this ZipArchive source, string destinationDirectoryName, IProgress<ZipProgress> progress, bool overwrite)
    {
        if (source == null)
            throw new ArgumentNullException(nameof(source));

        if (destinationDirectoryName == null)
            throw new ArgumentNullException(nameof(destinationDirectoryName));


        // Rely on Directory.CreateDirectory for validation of destinationDirectoryName.

        // Note that this will give us a good DirectoryInfo even if destinationDirectoryName exists:
        DirectoryInfo di = Directory.CreateDirectory(destinationDirectoryName);
        string destinationDirectoryFullPath = di.FullName;

        int count = 0;
        foreach (ZipArchiveEntry entry in source.Entries)
        {
            count++;
            string fileDestinationPath = Path.GetFullPath(Path.Combine(destinationDirectoryFullPath, entry.FullName));

            if (!fileDestinationPath.StartsWith(destinationDirectoryFullPath, StringComparison.OrdinalIgnoreCase))
                throw new IOException("File is extracting to outside of the folder specified.");

            var zipProgress = new ZipProgress(source.Entries.Count, count, entry.FullName);
            progress.Report(zipProgress);

            if (Path.GetFileName(fileDestinationPath).Length == 0)
            {
                // If it is a directory:

                if (entry.Length != 0)
                    throw new IOException("Directory entry with data.");

                Directory.CreateDirectory(fileDestinationPath);
            }
            else
            {
                // If it is a file:
                // Create containing directory:
                Directory.CreateDirectory(Path.GetDirectoryName(fileDestinationPath));
                entry.ExtractToFile(fileDestinationPath, overwrite: overwrite);
            }
        }
    }
}

这是用作

public class YourClass
{
    public Progress<ZipProgress> _progress;

    public YourClass()
    {
        // Create the progress object in the constructor, it will call it's ReportProgress using the sync context it was constructed on.
        // If your program is a UI program that means you want to new it up on the UI thread.
        _progress = new Progress<ZipProgress>();
        _progress.ProgressChanged += Report
    }

    private void Report(object sender, ZipProgress zipProgress)
    {
        //Use zipProgress here to update the UI on the progress.
    }

    //I assume you have a `Task.Run(() => Download(url, filePathDir);` calling this so it is on a background thread.
    public void Download(string url, string filePathDir)
    {
        WebClient wc = new WebClient();
        Stream zipReadingStream = wc.OpenRead(url);
        ZipArchive zip = new ZipArchive(zipReadingStream);
        zip.ExtractToDirectory(filePathDir, _progress);
    }

    //...

@ProGamersRo 我在代码示例中没有包括字段声明,因为我认为这是显而易见的必要步骤。我已经更新了示例。 - Scott Chamberlain
@cott Chamberlain,现在我遇到了一个错误:ReportProgress 错误信息: http://i.imgur.com/MiEW6l9.png - user7923477
这是一个笔误,我在网页浏览器中写了这个东西。应该是 ProgressChanged 而不是 ReportProgress。当发生这种情况时,你应该尝试检查文档。 - Scott Chamberlain
非常感谢!但是当我按下下载这些文件的按钮时,应用程序会冻结并且进度条显示为100%,这会成为一个问题吗? - user7923477
1
@madocter,您无法扩展静态类。该类不会继承ZipFileExtensions,它只是在ZipArchive上添加了一个扩展方法,我只是碰巧将其称为MyZipFileExtension,名称可以是任何东西。 - Scott Chamberlain
显示剩余14条评论

1
也许像这样的东西可以适合你:

using (var archive = new ZipArchive(zipReadingStream))
{
    var totalProgress = archive.Entries.Count;

    foreach (var entry in archive.Entries)
    {
        entry.ExtractToFile(destinationFileName); // specify the output path of thi entry

        // update progess there
    }
}

这只是一个简单的解决方法,用于跟踪进度。

请查看编辑。 - user7923477

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接