【问题标题】:Extract ZipFile Using C# With Progress Report使用带有进度报告的 C# 提取 ZipFile
【发布时间】:2022-04-05 14:28:25
【问题描述】:

谁能告诉我是否有可能(如果有,请举例说明)如何使用“ZipFile”(Ionic.邮编,http://dotnetzip.codeplex.com/)?

我的 WinForm 在从我选择的路径中提取 ZIP 文件到新路径方面做得很好在这段时间里,它好像被冻结了,但这只是因为它在后台解压缩 ZIP 文件。

ZIP 文件是一个大文件,我想通过添加并有一个进度条来显示解压缩如何使用准确的 ETA,从而减少对正在发生的事情的混淆。

这当然是可能的,我只是不知道如何在 C# WinForms 中做到这一点,我在网上看到了相当不错的外观,却没有真正找到适合我的示例。

这是我所拥有的一个粗略示例:

private void button1_Click(object sender, EventArgs e)
{
    var ROBOT0007 = textBox1.Text + @"\" + "ROBOT0007"; //ROBOT0007 folder
    var ROBOT_INSTALL = textBox1.Text + @"\" + "911" + @"\" + "files"; //ROBOT0007/911/files
    var ROBOT_INSTALL_SPECIAL = ROBOT_INSTALL + @"\" + "special.rar";  //ROBOT0007/911/files/special.rar

    //If the path has text...
    if (textBox1.TextLength > 0)
    {
        //if the subfolder doesn't exist then make it.
        if (!Directory.Exists(ROBOT0007))
        {
            Directory.CreateDirectory(ROBOT0007);
        }

        //if the textbox directory exists
        if (Directory.Exists(ROBOT0007))
        {
            using (ZipFile zip = ZipFile.Read(ROBOT_INSTALL_SPECIAL))
            {
                zip.ExtractAll(ROBOT0007, ExtractExistingFileAction.OverwriteSilently);

            } 
        }
    }
}

更新(2014 年 4 月 11 日):我已经删除了文本框,现在又回到了简单的基础,以下适用于后台工作人员,但是取消按钮对 RAR 文件没有影响......有什么建议吗?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Text;
using System.Windows.Forms;
using Ionic.Zip;
using System.IO;

namespace BackgroundWorkerSample
{
    // The BackgroundWorker will be used to perform a long running action
    // on a background thread.  This allows the UI to be free for painting
    // as well as other actions the user may want to perform.  The background
    // thread will use the ReportProgress event to update the ProgressBar
    // on the UI thread.
    public partial class Form1 : Form
    {
        /// <summary>
        /// The backgroundworker object on which the time consuming operation 
        /// shall be executed
        /// </summary>
        BackgroundWorker backgroundWorker1;

        public Form1()
        {
            InitializeComponent();
            backgroundWorker1 = new BackgroundWorker();

            // Create a background worker thread that ReportsProgress &
            // SupportsCancellation
            // Hook up the appropriate events.
            backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
            backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler
                    (backgroundWorker1_ProgressChanged);
            backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler
                    (backgroundWorker1_RunWorkerCompleted);
            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.WorkerSupportsCancellation = true;
        }

        /// <summary>
        /// On completed do the appropriate task
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // The background process is complete. We need to inspect
            // our response to see if an error occurred, a cancel was
            // requested or if we completed successfully.  
            if (e.Cancelled)
            {
                lblStatus.Text = "Task Cancelled.";
            }

            // Check to see if an error occurred in the background process.

            else if (e.Error != null)
            {
                lblStatus.Text = "Error while performing background operation.";
            }
            else
            {
                // Everything completed normally.
                lblStatus.Text = "Task Completed...";
            }

            //Change the status of the buttons on the UI accordingly
            btnStart.Enabled = true;
            btnCancel.Enabled = false;
        }

        /// <summary>
        /// Notification is performed here to the progress bar
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {

            // This function fires on the UI thread so it's safe to edit

            // the UI control directly, no funny business with Control.Invoke :)

            // Update the progressBar with the integer supplied to us from the

            // ReportProgress() function.  

            progressBar1.Value = e.ProgressPercentage;
            lblStatus.Text = "Processing......" + progressBar1.Value.ToString() + "%";
        }

        /// <summary>
        /// Time consuming operations go here </br>
        /// i.e. Database operations,Reporting
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            // The sender is the BackgroundWorker object we need it to
            // report progress and check for cancellation.
            //NOTE : Never play with the UI thread here...
            for (int i = 0; i < 100; i++)
            {
                //Thread.Sleep(100);
                string INSTALL_FOLDER= "C:" + @"\" + "Program Files (x86)" + @"\" + "Robot91111"+ @"\" + "basic" + @"\" + "string" + @"\" + "special.rar";
                string BURGOS_FOLDER = "C:" + @"\" + "Program Files (x86)" + @"\" + "Robot91111" + @"\" + "Burgos_Folder";
                if (!Directory.Exists(BURGOS_FOLDER))
                    {
                        Directory.CreateDirectory(BURGOS_FOLDER);
                        using (ZipFile zip = ZipFile.Read(INSTALL_FOLDER))
                        {
                            zip.ExtractAll(BURGOS_FOLDER, ExtractExistingFileAction.OverwriteSilently);
                        }
                    }

                // Periodically report progress to the main thread so that it can
                // update the UI.  In most cases you'll just need to send an
                // integer that will update a ProgressBar                    
                backgroundWorker1.ReportProgress(i);
                // Periodically check if a cancellation request is pending.
                // If the user clicks cancel the line
                // m_AsyncWorker.CancelAsync(); if ran above.  This
                // sets the CancellationPending to true.
                // You must check this flag in here and react to it.
                // We react to it by setting e.Cancel to true and leaving
                if (backgroundWorker1.CancellationPending)
                {
                    // Set the e.Cancel flag so that the WorkerCompleted event
                    // knows that the process was cancelled.
                    e.Cancel = true;
                    backgroundWorker1.ReportProgress(0);
                    return;
                }
            }

            //Report 100% completion on operation completed
            backgroundWorker1.ReportProgress(100);
        }

        private void btnStartAsyncOperation_Click(object sender, EventArgs e)
        {
            //Change the status of the buttons on the UI accordingly
            //The start button is disabled as soon as the background operation is started
            //The Cancel button is enabled so that the user can stop the operation 
            //at any point of time during the execution
            btnStart.Enabled = false;
            btnCancel.Enabled = true;

            // Kickoff the worker thread to begin it's DoWork function.
            backgroundWorker1.RunWorkerAsync();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {

                // Notify the worker thread that a cancel has been requested.

                // The cancel will not actually happen until the thread in the

                // DoWork checks the backgroundWorker1.CancellationPending flag. 

                backgroundWorker1.CancelAsync();
            }
        }
    }
} 

【问题讨论】:

  • 有人可以用这个和后台工作人员一起举个例子吗?每次我尝试使用“开始按钮”开始解压缩并使用“停止按钮”停止解压缩时,它都会由于文本框和标签而出现异常错误,如果我将它们注释掉,取消按钮会磨损,直到解压完成想法?
  • 您是否尝试过处理 zip.ExtractProgress 事件?
  • 你所看到的就是我所拥有的@Marton 你能尝试实现它吗?我不确定如何实现它。
  • 在项目的 codeplex 页面的 VB.Net 示例中显示:dotnetzip.codeplex.com

标签: c# winforms


【解决方案1】:
/*...*/
using (ZipFile zip = ZipFile.Read(ROBOT_INSTALL_SPECIAL))
        {
            zip.ExtractProgress += 
               new EventHandler<ExtractProgressEventArgs>(zip_ExtractProgress);
            zip.ExtractAll(ROBOT0007, ExtractExistingFileAction.OverwriteSilently);

        }
/*...*/

void zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
   if (e.TotalBytesToTransfer > 0)
   {
      progressBar1.Value = Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer);
   }
}

【讨论】:

  • 执行上述操作后,当我运行 exe 时出现错误:“BackgroundWorkerSample.exe 中发生了 'System.DivideByZeroException' 类型的异常,但未在用户代码中处理其他信息:尝试除以零。如果有针对此异常的处理程序,则程序可以安全地继续。”我不确定如何解决这个问题?我做了一个 try/catch 异常,然后当我运行它时,我没有收到任何错误,但是我回到正方形,取消按钮不会取消该过程...
  • @Burgo855 更新了我处理 DivideByZeroException 的答案。至于取消这个过程,你必须自己做一些研究,因为我不知道 DotNetZip 库。如果您仍然找不到解决方案,我建议您在 SO 上打开一个新问题。 StackOverflow 上的问题应该只解决一个特定的问题。
【解决方案2】:
private int totalFiles;
private int filesExtracted;

/*...*/

using (ZipFile zip = ZipFile.Read(ROBOT_INSTALL_SPECIAL))
{
    totalFiles = zip.Count;
    filesExtracted = 0;
    zip.ExtractProgress += ZipExtractProgress; 
    zip.ExtractAll(ROBOT0007, ExtractExistingFileAction.OverwriteSilently);
}

/*...*/

private void ZipExtractProgress(object sender, ExtractProgressEventArgs e)
{
    if (e.EventType != ZipProgressEventType.Extracting_BeforeExtractEntry)
        return;
    filesExtracted++;
    progressBar.Value = 100 * filesExtracted / totalFiles;
}

【讨论】:

  • 请尝试解释您的代码的作用。与接受的答案相比,它有什么不同?为什么需要这些更改?
  • 这是唯一对我有用的代码。它使用文件计数而不是传输的字节数来表示进度百分比。
  • 您仍然可以尝试解释代码的不同之处。
  • 此代码使用 zip 中的文件总数来确定进度,而不是传输的字节数,这似乎在每次提取新的 zip 条目时都会重置。
【解决方案3】:
使用 System.IO.Compression; 私有异步无效解压缩(字符串文件路径) { var _downloadPath = configuration.GetValue("DownloadPath"); var _extractPath = configuration.GetValue("ExtractPath"); var _extractPattern = configuration.GetValue("ExtractPattern"); Console.WriteLine($"Удаление старых файлов из директории: '{_extractPath}'"); var directoryInfo = new DirectoryInfo(_extractPath); foreach(directoryInfo.GetFiles() 中的 var 文件) { 文件.删除(); } Console.WriteLine($"Распаковка файла: '{filePath}'"); var 正则表达式 = 新正则表达式(_extractPattern); var fileList = new List(); var totalFiles = 0; var filesExtracted = 0; 使用 (var archive = await Task.Run(() => ZipFile.OpenRead(filePath))) { foreach(archive.Entries 中的 var 文件) { if (regex.IsMatch(file.Name)) { 文件列表。添加(文件); 总文件++; } } foreach(fileList 中的 var 文件) { Console.WriteLine($"Извлечение файла: '{file.Name}'"); 等待 Task.Run(() => { file.ExtractToFile($"{_extractPath}{file.Name}"); 文件提取++; var progress = Convert.ToInt32(100 * filesExtracted / totalFiles); Console.WriteLine($"Извлечено: {progress}%"); }); } } } appsettings.json 示例 { "下载路径": "f:\\download\\", "ExtractPath": "f:\\download\\extract\\", "ExtractPattern": "ACTSTAT.DBF|CENTERST.DBF|CURENTST.DBF|ESTSTAT.DBF|FLATTYPE.DBF|NDOCTYPE.DBF|OPERSTAT.DBF|ROOMTYPE.DBF|SOCRBASE.DBF|STRSTAT.DBF|[A-Z]{1 }16.DBF", }

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,但它没有解释为什么或如何回答这个问题。请include an explanation for your code,因为这确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。您可以使用edit 按钮改进此答案以获得更多选票和声誉!
【解决方案4】:
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{

    using (ZipFile zip = ZipFile.Read(@"edu.zip"))
    {
        totalFiles = zip.Count;
        filesExtracted = 0;
        zip.ExtractProgress += ZipExtractProgress;
        zip.ExtractAll(@"./", ExtractExistingFileAction.OverwriteSilently);
    }
    if (backgroundWorker1.CancellationPending)
    {

        e.Cancel = true;
        backgroundWorker1.ReportProgress(0);
        return;
    }
    backgroundWorker1.ReportProgress(100);
}

private void ZipExtractProgress(object sender, ExtractProgressEventArgs e)
{
    if (e.EventType != ZipProgressEventType.Extracting_BeforeExtractEntry)
        return;
    filesExtracted++;
    this.Dispatcher.Invoke(new Action(() =>
    {
        progressBar1.Value = 100 * filesExtracted / totalFiles;
    }));

}

void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        status.Content = "extractia a fost anulata";
    }
    else if (e.Error != null)
    {
        status.Content = "Ceva nu a mers ";
    }

}

void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
    status.Content = "Se dezarhiveaza......" + progressBar1.Value.ToString() + "%";
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    backgroundWorker1.RunWorkerAsync();
}

【讨论】:

  • 在它之前你需要 backgroundWorker1 = new BackgroundWorker(); backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); backgroundWorker1.ProgressChanged += 新 ProgressChangedEventHandler (backgroundWorker1_ProgressChanged); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler (backgroundWorker1_RunWorkerCompleted); backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.WorkerSupportsCancellation = true;
猜你喜欢
  • 2015-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-19
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多