C#:如何使用 rarlab 中的 unrar.dll & unrar.cs 来提取拆分存档?
C#: How to use unrar.dll & unrar.cs from rarlab to extract a split archive?
我已经下载了 unrar.dll for Windows software developers from rarlab.com,将 unrar.cs 的 unrar.dll 和 class 包含到我的 C# WPF 项目中。
它提取单个档案(即使设置了密码):
string source = "d:\unrartest\compressed\myarchive.part1.rar";
string dest = "d:\unrartest\extracted";
Unrar unrar = new Unrar();
unrar.Password = "password_of_myarchive";
unrar.Open(@source, Unrar.OpenMode.Extract);
while (unrar.ReadHeader())
{
unrar.ExtractToDirectory(@dest);
}
unrar.Close();
...但不是拆分的:
System.IO.IOException: "File CRC Error"
周围没有资料,想知道
- 如何处理
unrar.ReadHeader()
进行下一步
拆分存档的文件
- 一般情况下如何确定拆分存档的第一个文件
- (optional)如何判断整体提取进度
进程(在运行时输出我的程序的进度)
解决方案:
基本上,它与上面评论中@Viezevingertjes 所建议的 SharpCompress 一起使用。但不幸的是,SharpCompress 还不支持 RAR5 解密,这意味着 RAR5 密码保护的文件根本不会被提取,因此 SharpCompress 的使用受到限制。
作为解决方法,您只能通过这样的进程调用直接使用 rar.exe、unrar.exe 或 winrar.exe:
string rarExec = "\"c:\Program Files\WinRAR\Rar.exe\"";
string sourceRar = "\"c:\sourceFolder\myfile.part001.rar\"";
string targetPath = "\"c:\destinationFolder\"";
string password = "topsecret";
using (System.Diagnostics.Process process = new System.Diagnostics.Process())
{
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = rarExec;
if (password != "")
process.StartInfo.Arguments = "/c x -cfg- -inul -y " + "-p" + password + sourceRar + " " + targetPath;
else
process.StartInfo.Arguments = "/c x -cfg- -inul -y " + sourceRar + " " + targetPath;
process.Start();
process.WaitForExit();
switch (process.ExitCode)
{
case 0:
// "OK: extracted";
break;
case 10:
// "Error: wrong password";
break;
default:
// "Error: unknown";
break;
}
}
unrardll 中包含的 c# 包装器和示例已过时,并且不能很好地处理多卷 rar 文件,因为有未处理的新回调消息。要修复它,请更改:
private enum CallbackMessages : uint
{
VolumeChange = 0,
ProcessData = 1,
NeedPassword = 2
}
至
private enum CallbackMessages : uint
{
VolumeChange=0,
ProcessData=1,
NeedPassword=2,
VolumeChangeW = 3,
NeedPasswordW = 4,
}
并处理 VolumeChangeW 的新回调消息:
private int RARCallback(uint msg, int UserData, IntPtr p1, int p2)
{
string volume=string.Empty;
string newVolume=string.Empty;
int result=-1;
switch((CallbackMessages)msg)
{
case CallbackMessages.VolumeChange:
case CallbackMessages.VolumeChangeW:
if ((CallbackMessages)msg == CallbackMessages.VolumeChange)
volume =Marshal.PtrToStringAnsi(p1);
else
volume = Marshal.PtrToStringAuto(p1);
if ((VolumeMessage)p2==VolumeMessage.Notify)
result=OnNewVolume(volume);
else if((VolumeMessage)p2==VolumeMessage.Ask)
{
newVolume=OnMissingVolume(volume);
if(newVolume.Length==0)
result=-1;
else
{
if(newVolume!=volume)
{
for(int i=0; i<newVolume.Length; i++)
{
Marshal.WriteByte(p1, i, (byte)newVolume[i]);
}
Marshal.WriteByte(p1, newVolume.Length, (byte)0);
}
result=1;
}
}
break;
case CallbackMessages.ProcessData:
result=OnDataAvailable(p1, p2);
break;
case CallbackMessages.NeedPassword:
result=OnPasswordRequired(p1, p2);
break;
default:
break;
}
return result;
}
我遇到了这个问题,希望能解决我所有的问题。但我刚刚找到我的解决方案并愿意分享。
- how to handle unrar.ReadHeader() to proceed with the next file of a split archive
如果您使用的是 Unrar 中的 C# 示例,则应删除 ProcessFileError()
中的 IOException("File CRC Error")
或抛出错误。如果您以读取模式打开,文件打开错误也是如此。
如果 continuedOnNext == false
.
case RARError.BadData:
if (!currentFile.continuedOnNext) throw new IOException("File CRC Error");
else break;
下一个文件将是完全相同的文件名并将成功提取(假设第 2 部分中的文件未损坏)。请注意,如果列出新文件,则需要修改 ReadHeader()
:
中的此语句
// Determine if new file
if (((header.Flags & 0x01) != 0) && currentFile != null)
currentFile.ContinuedFromPrevious = true;
为此:
// Determine if new file
if ((header.Flags & 0x01) != 0) return true;
如果不想停止 while read 循环,则需要 return true。
how to determine the first file of a split archive, in general
如果您的意思是如何确定存档是否是第一卷,您应该将 Unrar.cs、archiveFlags
中的私有 属性 更改为更易于访问的修饰符(例如:内部或 public).
检查它是否是 volume/split 存档:
bool isVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.Volume) == RAR.ArchiveFlags.Volume
检查它是否是第一个 volume/split 存档:
bool isFirstVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.FirstVolume) == RAR.ArchiveFlags.FirstVolume
how to determine the progress of the overall extraction process (to output the progress in my program during runtime)
您可以使用 ListFiles
获取存档文件计数并将其用作主要的存档提取过程。然后为 RARObj.ExtractionProgress
提取并创建一个事件以更新您拥有的任何 ProgressBar。
ExtractionProgressEventArgs e
有 属性 PercentComplete
供您更新进度条。我建议您分析 WinRAR 应用程序是如何工作的,这样您就可以更好地了解它是如何工作的。
哦还有一件事。
RAR RARObj = new Unrar(archive.path);
我已经下载了 unrar.dll for Windows software developers from rarlab.com,将 unrar.cs 的 unrar.dll 和 class 包含到我的 C# WPF 项目中。
它提取单个档案(即使设置了密码):
string source = "d:\unrartest\compressed\myarchive.part1.rar";
string dest = "d:\unrartest\extracted";
Unrar unrar = new Unrar();
unrar.Password = "password_of_myarchive";
unrar.Open(@source, Unrar.OpenMode.Extract);
while (unrar.ReadHeader())
{
unrar.ExtractToDirectory(@dest);
}
unrar.Close();
...但不是拆分的:
System.IO.IOException: "File CRC Error"
周围没有资料,想知道
- 如何处理
unrar.ReadHeader()
进行下一步 拆分存档的文件 - 一般情况下如何确定拆分存档的第一个文件
- (optional)如何判断整体提取进度 进程(在运行时输出我的程序的进度)
解决方案:
基本上,它与上面评论中@Viezevingertjes 所建议的 SharpCompress 一起使用。但不幸的是,SharpCompress 还不支持 RAR5 解密,这意味着 RAR5 密码保护的文件根本不会被提取,因此 SharpCompress 的使用受到限制。
作为解决方法,您只能通过这样的进程调用直接使用 rar.exe、unrar.exe 或 winrar.exe:
string rarExec = "\"c:\Program Files\WinRAR\Rar.exe\"";
string sourceRar = "\"c:\sourceFolder\myfile.part001.rar\"";
string targetPath = "\"c:\destinationFolder\"";
string password = "topsecret";
using (System.Diagnostics.Process process = new System.Diagnostics.Process())
{
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.StartInfo.FileName = rarExec;
if (password != "")
process.StartInfo.Arguments = "/c x -cfg- -inul -y " + "-p" + password + sourceRar + " " + targetPath;
else
process.StartInfo.Arguments = "/c x -cfg- -inul -y " + sourceRar + " " + targetPath;
process.Start();
process.WaitForExit();
switch (process.ExitCode)
{
case 0:
// "OK: extracted";
break;
case 10:
// "Error: wrong password";
break;
default:
// "Error: unknown";
break;
}
}
unrardll 中包含的 c# 包装器和示例已过时,并且不能很好地处理多卷 rar 文件,因为有未处理的新回调消息。要修复它,请更改:
private enum CallbackMessages : uint
{
VolumeChange = 0,
ProcessData = 1,
NeedPassword = 2
}
至
private enum CallbackMessages : uint
{
VolumeChange=0,
ProcessData=1,
NeedPassword=2,
VolumeChangeW = 3,
NeedPasswordW = 4,
}
并处理 VolumeChangeW 的新回调消息:
private int RARCallback(uint msg, int UserData, IntPtr p1, int p2)
{
string volume=string.Empty;
string newVolume=string.Empty;
int result=-1;
switch((CallbackMessages)msg)
{
case CallbackMessages.VolumeChange:
case CallbackMessages.VolumeChangeW:
if ((CallbackMessages)msg == CallbackMessages.VolumeChange)
volume =Marshal.PtrToStringAnsi(p1);
else
volume = Marshal.PtrToStringAuto(p1);
if ((VolumeMessage)p2==VolumeMessage.Notify)
result=OnNewVolume(volume);
else if((VolumeMessage)p2==VolumeMessage.Ask)
{
newVolume=OnMissingVolume(volume);
if(newVolume.Length==0)
result=-1;
else
{
if(newVolume!=volume)
{
for(int i=0; i<newVolume.Length; i++)
{
Marshal.WriteByte(p1, i, (byte)newVolume[i]);
}
Marshal.WriteByte(p1, newVolume.Length, (byte)0);
}
result=1;
}
}
break;
case CallbackMessages.ProcessData:
result=OnDataAvailable(p1, p2);
break;
case CallbackMessages.NeedPassword:
result=OnPasswordRequired(p1, p2);
break;
default:
break;
}
return result;
}
我遇到了这个问题,希望能解决我所有的问题。但我刚刚找到我的解决方案并愿意分享。
- how to handle unrar.ReadHeader() to proceed with the next file of a split archive
如果您使用的是 Unrar 中的 C# 示例,则应删除 ProcessFileError()
中的 IOException("File CRC Error")
或抛出错误。如果您以读取模式打开,文件打开错误也是如此。
如果 continuedOnNext == false
.
case RARError.BadData:
if (!currentFile.continuedOnNext) throw new IOException("File CRC Error");
else break;
下一个文件将是完全相同的文件名并将成功提取(假设第 2 部分中的文件未损坏)。请注意,如果列出新文件,则需要修改 ReadHeader()
:
// Determine if new file
if (((header.Flags & 0x01) != 0) && currentFile != null)
currentFile.ContinuedFromPrevious = true;
为此:
// Determine if new file
if ((header.Flags & 0x01) != 0) return true;
如果不想停止 while read 循环,则需要 return true。
how to determine the first file of a split archive, in general
如果您的意思是如何确定存档是否是第一卷,您应该将 Unrar.cs、archiveFlags
中的私有 属性 更改为更易于访问的修饰符(例如:内部或 public).
检查它是否是 volume/split 存档:
bool isVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.Volume) == RAR.ArchiveFlags.Volume
检查它是否是第一个 volume/split 存档:
bool isFirstVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.FirstVolume) == RAR.ArchiveFlags.FirstVolume
how to determine the progress of the overall extraction process (to output the progress in my program during runtime)
您可以使用 ListFiles
获取存档文件计数并将其用作主要的存档提取过程。然后为 RARObj.ExtractionProgress
提取并创建一个事件以更新您拥有的任何 ProgressBar。
ExtractionProgressEventArgs e
有 属性 PercentComplete
供您更新进度条。我建议您分析 WinRAR 应用程序是如何工作的,这样您就可以更好地了解它是如何工作的。
哦还有一件事。
RAR RARObj = new Unrar(archive.path);