首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#:如何使用rarlab中的unrar.dll & unrar.cs提取拆分存档?

C#:如何使用rarlab中的unrar.dll & unrar.cs提取拆分存档?
EN

Stack Overflow用户
提问于 2020-01-03 09:36:19
回答 3查看 1.6K关注 0票数 1

我从rarlab.com下载了rarlab.com,包括unrar.dll和unrar.cs类到我的C# WPF项目中。

它提取单个档案(即使设置了密码):

代码语言:javascript
复制
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();

..。但不是分裂的:

代码语言:javascript
复制
System.IO.IOException: "File CRC Error"

由于这里没有文件,我想知道

  1. 如何处理unrar.ReadHeader()以继续处理拆分存档的下一个文件
  2. 通常,如何确定拆分存档的第一个文件
  3. (可选)如何确定整个提取过程的进度(以便在运行时在我的程序中输出进度)
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-05-05 09:28:52

unrardll中包含的c#包装器和示例已经过时,不能很好地处理多卷rar文件,因为有新的回调消息无法处理。要修复它,请更改:

代码语言:javascript
复制
private enum CallbackMessages : uint
{
    VolumeChange = 0,
    ProcessData = 1,
    NeedPassword = 2
}

代码语言:javascript
复制
private enum CallbackMessages : uint
{
    VolumeChange=0,
    ProcessData=1,
    NeedPassword=2,
    VolumeChangeW = 3,
    NeedPasswordW = 4,
}

并处理VolumeChangeW的新回调消息:

代码语言:javascript
复制
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;
}
票数 3
EN

Stack Overflow用户

发布于 2021-08-08 21:45:27

我偶然发现了这个问题,希望能找到我所有问题的答案。但我找到了我的解决方案并愿意分享。

  1. 如何处理unrar.ReadHeader()以继续处理拆分存档的下一个文件

如果使用Unrar中的C#示例,则应该删除ProcessFileError()中的IOException("File CRC Error")或抛出错误。如果您在读取模式下打开文件,那么文件打开错误也是一样的。如果continuedOnNext == false.

代码语言:javascript
复制
case RARError.BadData:
    if (!currentFile.continuedOnNext) throw new IOException("File CRC Error");
    else break;

下一个文件将是完全相同的文件名,并将成功提取(假设第2部分中的文件没有损坏)。请注意,如果列出新文件,则需要在ReadHeader()中修改此语句

代码语言:javascript
复制
// Determine if new file
if (((header.Flags & 0x01) != 0) && currentFile != null)
        currentFile.ContinuedFromPrevious = true;

对此:

代码语言:javascript
复制
// Determine if new file
if ((header.Flags & 0x01) != 0) return true;

如果不想停止while循环,则希望返回true。

通常,如何确定拆分存档的第一个文件

如果您的意思是如何确定归档是否是第一个卷,则应该将Unrar.cs,archiveFlags中的私有属性更改为更容易访问的修饰符(例如:内部或公共)。

若要检查它是否为卷/拆分存档,请执行以下操作:

代码语言:javascript
复制
bool isVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.Volume) == RAR.ArchiveFlags.Volume

要检查它是否是第一个卷/拆分存档:

代码语言:javascript
复制
bool isFirstVolume = (RARObj.archiveFlags & RAR.ArchiveFlags.FirstVolume) == RAR.ArchiveFlags.FirstVolume

如何确定整个提取过程的进度(以便在运行时在我的程序中输出进度)

您可以使用ListFiles获取归档文件计数,并将其用作主存档提取过程。然后提取并为RARObj.ExtractionProgress创建一个事件,以更新您拥有的任何ProgressBar。

ExtractionProgressEventArgs e为您提供了用于更新进度条的属性PercentComplete。我建议您分析一下WinRAR应用程序是如何做到的,这样您就可以更好地了解它是如何工作的。

还有一件事。

代码语言:javascript
复制
RAR RARObj = new Unrar(archive.path);
票数 1
EN

Stack Overflow用户

发布于 2020-01-06 16:53:09

解决方案:

基本上,它与@Viezevingertjes在上面的注释中建议的SharpCompress一起工作。但不幸的是,SharpCompress还不支持RAR5解密,这意味着根本不提取RAR5密码保护的文件,因此SharpCompress的使用有限。

作为解决办法,您只能通过这样的进程调用直接使用rar.exe、unrar.exe或winrar.exe:

代码语言:javascript
复制
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;
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59576125

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档