C# OpenFileDialog 打开包含单个文件的 zip 文件夹?

C# OpenFileDialog open zip folder containing single file?

我有一个应用程序,该应用程序目前为用户提供了在应用程序中查看 PDF 文件的能力,方法是使用文件 -> 打开,使用 Microsoft.Win32.OpenFileDialog 浏览到 PDF 文件的位置,然后在 GUI 的 System.Windows.Controls.WebBrowser 中显示该 PDF 文件。

我正在创建 OpenFileDialog 并设置它可以打开的文件扩展名:

/*Create Open File dialog */
        Microsoft.Win32.OpenFileDialog OFDlg = new Microsoft.Win32.OpenFileDialog();

        /*Set filter for file extension and default file extension */
        OFDlg.DefaultExt = ".pdf";
        OFDlg.Filter = "PDF Documents (.pdf)|*.pdf";

我现在想扩展它,以便用户可以打开包含单个 PDF 文档的 ZIP 文件夹,并以与我上面相同的方式显示该 PDF 文档。

我尝试更改过滤器以允许 .zip 文件,即

OFDlg.DefaultExt = ".pdf|.zip";
OFDlg.Filter = "PDF Documents (.pdf)|*.pdf|ZIP|*.zip";

但是当我浏览到 OpenFileDialog 中 .zip 文件的位置时,那里没有显示 .zip 文件夹 - 只有普通文件夹和 PDF 文档(该目录中的其他文档,例如 . OpenFileDialog).

中不显示 doc & .xls

我希望能够直接从 .zip 打开 .zip 文件的内容,而不是导航到该文件本身的原因是,我可以将 public/private 密钥加密添加到.zip,以便其内容只能被安全地读取。

我知道如果 .zip 包含多个文件,理论上可能会出现问题,但我打算将每个加密文件发送到其自己的 zip 文件夹中,因此可以假设用户可以发送任何 zip 文件正在尝试打开包含一个 .pdf,没有其他内容。

所以我的问题是:

  1. 如何使 .zip 文件夹在 OpenFileDialog 中可见?
  2. 如何在我当前用于在我的 GUI 中显示 PDF 的 System.Window.Controls.WebBrowser 中自动打开该 .zip 文件夹并显示其内容(单个 PDF 文件)?

编辑 1

我尝试将 OpenFile() 方法更改为以下代码:

/*Set filter for file extension and default file extension */
        OFDlg.DefaultExt = ".pdf";
        OFDlg.DefaultExt = ".zip";
        OFDlg.Filter = "PDF Documents (.pdf)|*.pdf";
        OFDlg.Filter = "ZIP Folders (.ZIP)|*.zip";

但是当我现在 运行 我的应用程序并浏览到同一位置时,虽然 .zip 文件夹现在显示在 OpenFileDialog 中,但 .pdf 文件不再...如果我双击 .zip 文件夹,我的应用程序就会中断,我会在行

上收到 运行时间错误
PdfPanel.OpenFile(docFP);

上面写着:

An unhandled exception of type 'System.AccessViolationException' occurred in MoonPdfLib.dll

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

我想这与我用来阅读 PDF 的 MoonPDF 库无法处理 .zip 扩展名有关吗?

我该如何解决才能打开 ZIP 中的 PDF?

编辑 2

好的,我已经解决了只能看到 PDF 文件或 .ZIP 文件夹(不能同时看到两者)的问题,方法是将功能转移到两种不同的方法中 - 一种用于显示直接从 PDF 的文件路径显示 PDF,另一个从保存它的 .ZIP 文件夹的路径显示 PDF。

目前直接显示PDF的方法是可行的(本质上就是我引用的第一段代码中的代码)。然而,从 ZIP 显示 PDF 的方法目前不起作用...

我理解这样做的原因 - 这是因为我正在将 .zip 文件夹传递给 OpenFile 方法...此方法的代码目前如下所示:

private void openZipMenuItem_click(object sender, RoutedEventArgs e)
    {
        Microsoft.Win32.OpenFileDialog OZipDlg = new Microsoft.Win32.OpenFileDialog();

        OZipDlg.DefaultExt = ".zip";
        OZipDlg.Filter = "ZIP Folder (.zip)|*.zip";

        Nullable<bool> result = OZipDlg.ShowDialog();

        if (result == true)
        {
            /*Open document */
            string filename = OZipDlg.FileName;
            //fnTextBox.Text = filename;
            zipFP = OZipDlg.FileName;
            /*browser.Navigate(docFP); ERF (27/05/2016 @ 0935) Comment this line- I want to use PdfPanel to open docFP, not browser */

            Console.WriteLine("Panel height: " + PdfPanel.ActualHeight);
            PdfPanel.OpenFile(zipFP);

        }
    }

当我尝试调用此函数打开 .zip 时,出现 运行time 异常,其中显示:

AccessViolationException was unhandled

An unhandled exception of type 'System.AccessViolationException' occurred in MoonPdfLib.dll

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

我知道我无法在 PdfPanel 中显示 Zip 文件夹(这是我在 MoonPdfLibrary 中使用的 MoonPdfPanel),所以我知道我这里会得到异常。

如何将 zipFP 的内容传递给 PdfPanel.OpenFile() 的调用,而不是将 zipFP 本身传递给它?

编辑 3

好的,所以当我打开 ZIP 文件夹时,我的代码当前正在成功提取 PDF 文件 - 我可以看到它已复制到我指定的目录中。我现在正在尝试让 PDF 在我的应用程序的 PDF 面板中自动显示 - 我通过添加以下代码完成了此操作:

try{
    string extractPath = @"C:\Documents";
    using(ZipArchivev zip = ZipFile.Open(zipFP, ZipArchiveMode.Read))
        foreach(ZipArchiveEntry entry in zip.Entries){
            try{
                ZipFile.ExtractToDirectory(zipFP, extractPath);
                Console.WriteLine("zipFP: " + zipFP);
            }catch(System.IOException){
                Console.WriteLine("File already exists...");
            }
        }

        string ExtractedPDF = string.Concat(extractPath, zipFP);
        PdfPanel.OpenFile(ExtractedPDF);
}catch(AccessViolationException ex){
    Console.WriteLine("Can't display a zip in the PDF panel..." + ex.InnerException);
}

但是当我的代码尝试执行行 PdfPanel.OpenFile(ExtracedPDF); 时,我得到一个异常:

FileNotFoundException was unhandled | An unhandled exception of type 'System.IO.FileNotFoundException' occurred in MoonPdfLib.dll'

我知道发生这种情况是因为我试图在 PDFPanel 中显示的变量 ExtractedPDF 实际上保存的是包含 PDF 的文件夹的路径,而不是 PDF 本身 - 我该如何给它PDF 文件的名称,当我实际上不知道 PDF 文件将被称为什么时?

首先,关于在打开文件对话框中显示文件。您最初执行此操作的方法是正确的。您更新后的代码现在首先设置过滤器以显示 PDF,然后将该过滤器替换为显示 zip 文件的过滤器。标准文件打开对话框并非设计用于同时显示不同的文件类型。正确的处理方式是让用户选择他们想要显示的文件类型。

通常,还会添加一个 "All files" 选项(使用 . 作为搜索模式)。这样,如果用户想要打开的文件类型在列表中不可用,他们也可以看到它。

关于打开zip文件中的PDF文件,您需要自行解压PDF文件。 This question 有一些选项可以做到这一点。

这里有一些与您的请求类似的东西,代码背后的逻辑是:

  • 仅显示 OpenFileDialog
  • 中的 zip 和 pdf 文件
  • 如果用户选择了 pdf 文件,则在面板中显示它
  • 如果用户选择了 zip 文件,请将 OpenFileDialog 的目录更改为 zip 文件(将其视为文件夹)

示例代码(工作代码....):

 OpenFileDialog ofd = new OpenFileDialog();
 ofd.Filter = "PDF files (.pdf)|*.pdf;*.zip";
 ofd.ShowDialog();

 //reopen OpenFileDialog if it is zip file. this part can be improved.
 if (ofd.FileName.EndsWith(".zip")) 
 {
     ofd.InitialDirectory = ofd.FileName;
     ofd.ShowDialog();
 }

 //if it's a PDF, note that you don't really need this check, 
 //as the only file can reache here will be a PDF, 
 //and it can be the temporary file that inside a zip. 
 if(ofd.FileName.EndsWith(".pdf"))
 {
    //show it in your PdfPanel
 }

根据您的新评论和添加的代码进行编辑。您需要将代码更改为以下内容,因为您当前的代码是错误的文件目录:

try{
    string extractPath = @"C:\Documents";
    string ExtractedPDF ="";
    using(ZipArchivev zip = ZipFile.Open(zipFP, ZipArchiveMode.Read))
        foreach(ZipArchiveEntry entry in zip.Entries){
            try{
                ExtractedPDF= Path.Combine(extractPath, entry.FullName);
                entry.ExtractToFile(ExtractedPDF,true);

            }catch(System.IOException){
                Console.WriteLine("error during extraction...");
            }
        } 
        if( System.IO.File.Exists(ExtractedPDF))
        {
             PdfPanel.OpenFile(ExtractedPDF);
        }
}catch(AccessViolationException ex){
    Console.WriteLine("Can't display a zip in the PDF panel..." + ex.InnerException);
}

如果你想在打开的文件对话框中支持多种文件格式,你需要添加第三个(或更好的第一个)选项,它聚合了所有支持的文件扩展名:

OFDlg.Filter = "Supported file formats|*.pdf;*.zip|PDF Documents|*.pdf|ZIP files|*.zip";