使用活动进度条 C# 解压缩文件
Unzip File with active progress bar C#
我正在尝试创建一个自定义安装程序,以将 zip 文件从固定位置提取到我访问过的用户首选位置,并找到了许多来源,但所有这些都不起作用。
应用程序在解压缩包时冻结并且直到其 100% 完成才更新进度条的问题(我认为不是很有用)
这是我目前所拥有的
void Install()
{
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(Constants.UpdateZipPath))
{
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(Zip_ExtractProgress);
zip.ExtractAll(installDir, ExtractExistingFileAction.OverwriteSilently);
}
}
void Zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.TotalBytesToTransfer > 0)
{
ProgressBar.Value = Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer);
}
}
这是我找到的来源之一,但不起作用Extract ZipFile Using C# With Progress Report
当我尝试使用时 Task.Factory.StartNew(() => Install());
我得到这个错误
Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll
Exception thrown: 'System.InvalidOperationException' in DotNetZip.dll
我正在使用 Ionic.Zip.ZipFile
,当我在主线程之外使用它时它不起作用
您不应该直接更新 ProgressBar
值,除非您的代码是 运行 在主线程中。
以下 extension methods 调用必要的辅助例程来规避此限制:
public static class ProgressBarExtensions
{
// this extension method can be used for any Control which supports
// InvokeRequired() and BeginInvoke()
public static void EnsureInvokeAsync(this Control control, Action action)
{
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action();
}
}
public static void SetProgressValue(this ProgressBar progressBar, int progressValue)
{
//
// the lambda will capture the argument in a closure
// the compiler does all the hard work for you
progressBar.EnsureInvokeAsync(() => progressBar.Value = progressValue);
}
}
调用示例:
progressBar1.SetProgressValue(myValue);
我确实让它与 Axel Kemper
一起工作,但我必须在开始解压缩之前启动一个线程,这是我想出的代码!
public class MyClass
{
public bool InstallIsCompleted = false;
public string CurrentFileBeingExtracted = "";
public int TotalNumberOfFiles = 1;
public int NumberOfFilesTransferred = 1;
public void MyFunction()
{
new Thread(Update).Start();
Task.Factory.StartNew(() => Install());
}
void Update()
{
while (!InstallIsCompleted)
{
Dispatcher.Invoke(() =>
{
// updates UI text elements including the display for which file
// is being extracted and the total progress of the total extraction
DisplayCurrentFile.Text = CurrentFileBeingExtracted;
float Percentage = (NumberOfFilesTransferred*100) / TotalNumberOfFiles;
InstallationProgressBar.Value = Percentage + (SecondProgressBar.Value * (1 / TotalNumberOfFiles));
});
}
//Install Completed
/* other code here */
}
void Install(string ZipPath, string TargetPath)
{
using (ZipFile zip = ZipFile.Read(ZipPath))
{
// initial setup before extraction
TotalNumberOfFiles= zip.Entries.Count;
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(Zip_ExtractProgress);
// actual extraction process
zip.ExtractAll(TargetPath, ExtractExistingFileAction.OverwriteSilently);
// since the boolean below is in the same "thread" the extraction must
// complete for the boolean to be set to true
InstallIsCompleted = true;
}
}
void Zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
// must be above 0 to prevent *divide by 0 error
if (e.TotalBytesToTransfer > 0)
{
// If file has completed transfer, update the number of files transferred
if (Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer) >= 100)
{
NumberOfFilesTransferred++;
}
// updates the current file being exracted
CurrentFileBeingExtracted = e.CurrentEntry.FileName.Replace("zip::", "");
// updates the progress
ProgressBarExtensions.SetProgressValue(InstallationProgressBar, Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer));
}
}
}
public static class ProgressBarExtensions
{
// this extension method can be used for any Control which supports
// InvokeRequired() and BeginInvoke()
public static void EnsureInvokeAsync(this Control control, Action action)
{
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action();
}
}
public static void SetProgressValue(this ProgressBar progressBar, int progressValue)
{
//
// the lambda will capture the argument in a closure
// the compiler does all the hard work for you
progressBar.EnsureInvokeAsync(() => progressBar.Value = progressValue);
}
}
虽然进度计算不是 100% 准确,但它 100% 像我希望的那样工作,因为它将总大小除以文件数,所以 1mb zip 中的 10kb 文件可能是如果只有4个文件占25%完成度
由于某些原因e.TotalBytesToTransfer
只计算每个文件,我不确定在提取前是否有可靠的方法来计算提取大小,所以在这种情况下它只能获得提取进度每个文件,并计算有多少个文件
我正在尝试创建一个自定义安装程序,以将 zip 文件从固定位置提取到我访问过的用户首选位置,并找到了许多来源,但所有这些都不起作用。 应用程序在解压缩包时冻结并且直到其 100% 完成才更新进度条的问题(我认为不是很有用)
这是我目前所拥有的
void Install()
{
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(Constants.UpdateZipPath))
{
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(Zip_ExtractProgress);
zip.ExtractAll(installDir, ExtractExistingFileAction.OverwriteSilently);
}
}
void Zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.TotalBytesToTransfer > 0)
{
ProgressBar.Value = Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer);
}
}
这是我找到的来源之一,但不起作用Extract ZipFile Using C# With Progress Report
当我尝试使用时 Task.Factory.StartNew(() => Install());
我得到这个错误
Exception thrown: 'System.InvalidOperationException' in WindowsBase.dll
Exception thrown: 'System.InvalidOperationException' in DotNetZip.dll
我正在使用 Ionic.Zip.ZipFile
,当我在主线程之外使用它时它不起作用
您不应该直接更新 ProgressBar
值,除非您的代码是 运行 在主线程中。
以下 extension methods 调用必要的辅助例程来规避此限制:
public static class ProgressBarExtensions
{
// this extension method can be used for any Control which supports
// InvokeRequired() and BeginInvoke()
public static void EnsureInvokeAsync(this Control control, Action action)
{
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action();
}
}
public static void SetProgressValue(this ProgressBar progressBar, int progressValue)
{
//
// the lambda will capture the argument in a closure
// the compiler does all the hard work for you
progressBar.EnsureInvokeAsync(() => progressBar.Value = progressValue);
}
}
调用示例:
progressBar1.SetProgressValue(myValue);
我确实让它与 Axel Kemper
一起工作,但我必须在开始解压缩之前启动一个线程,这是我想出的代码!
public class MyClass
{
public bool InstallIsCompleted = false;
public string CurrentFileBeingExtracted = "";
public int TotalNumberOfFiles = 1;
public int NumberOfFilesTransferred = 1;
public void MyFunction()
{
new Thread(Update).Start();
Task.Factory.StartNew(() => Install());
}
void Update()
{
while (!InstallIsCompleted)
{
Dispatcher.Invoke(() =>
{
// updates UI text elements including the display for which file
// is being extracted and the total progress of the total extraction
DisplayCurrentFile.Text = CurrentFileBeingExtracted;
float Percentage = (NumberOfFilesTransferred*100) / TotalNumberOfFiles;
InstallationProgressBar.Value = Percentage + (SecondProgressBar.Value * (1 / TotalNumberOfFiles));
});
}
//Install Completed
/* other code here */
}
void Install(string ZipPath, string TargetPath)
{
using (ZipFile zip = ZipFile.Read(ZipPath))
{
// initial setup before extraction
TotalNumberOfFiles= zip.Entries.Count;
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(Zip_ExtractProgress);
// actual extraction process
zip.ExtractAll(TargetPath, ExtractExistingFileAction.OverwriteSilently);
// since the boolean below is in the same "thread" the extraction must
// complete for the boolean to be set to true
InstallIsCompleted = true;
}
}
void Zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
// must be above 0 to prevent *divide by 0 error
if (e.TotalBytesToTransfer > 0)
{
// If file has completed transfer, update the number of files transferred
if (Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer) >= 100)
{
NumberOfFilesTransferred++;
}
// updates the current file being exracted
CurrentFileBeingExtracted = e.CurrentEntry.FileName.Replace("zip::", "");
// updates the progress
ProgressBarExtensions.SetProgressValue(InstallationProgressBar, Convert.ToInt32(100 * e.BytesTransferred / e.TotalBytesToTransfer));
}
}
}
public static class ProgressBarExtensions
{
// this extension method can be used for any Control which supports
// InvokeRequired() and BeginInvoke()
public static void EnsureInvokeAsync(this Control control, Action action)
{
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action();
}
}
public static void SetProgressValue(this ProgressBar progressBar, int progressValue)
{
//
// the lambda will capture the argument in a closure
// the compiler does all the hard work for you
progressBar.EnsureInvokeAsync(() => progressBar.Value = progressValue);
}
}
虽然进度计算不是 100% 准确,但它 100% 像我希望的那样工作,因为它将总大小除以文件数,所以 1mb zip 中的 10kb 文件可能是如果只有4个文件占25%完成度
由于某些原因e.TotalBytesToTransfer
只计算每个文件,我不确定在提取前是否有可靠的方法来计算提取大小,所以在这种情况下它只能获得提取进度每个文件,并计算有多少个文件