【问题标题】:C# OpenFileDialog open zip folder containing single file?C# OpenFileDialog 打开包含单个文件的 zip 文件夹?
【发布时间】:2016-10-02 06:42:09
【问题描述】:

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

我正在创建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 文档(该目录中的其他文档,例如 .doc 和 .xls不显示在OpenFileDialog)。

我希望能够直接从 .zip 打开 .zip 文件的内容,而不是导航到该文件本身的原因是,我可以向 .zip 添加公钥/私钥加密,所以它的内容只能被安全读取。

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

所以我的问题是:

  1. 如何使 .zip 文件夹从 OpenFileDialog 可见?
  2. 如何使选择的 .zip 文件夹自动打开并在 System.Window.Controls.WebBrowser 中显示其内容(单个 PDF 文件),我目前正在使用该文件夹在我的 GUI 中显示 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);

上面写着:

MoonPdfLib.dll 中出现“System.AccessViolationException”类型的未处理异常

附加信息:试图读取或写入受保护的内存。这通常表明其他内存已损坏。

我想这与我用来阅读 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 文件时,我得到一个运行时异常,上面写着:

AccessViolationException 未处理

MoonPdfLib.dll 中出现“System.AccessViolationException”类型的未处理异常

附加信息:试图读取或写入受保护的内存。这通常表明其他内存已损坏。

我知道我无法在 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 未处理 | MoonPdfLib.dll 中发生了“System.IO.FileNotFoundException”类型的未处理异常

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

【问题讨论】:

  • 您添加的过滤器应该在打开的对话框中的“文件类型”组合框中添加两个选项 - 一个用于 PDF,一个用于 zip 文件。如果您选择 zip 文件选项,是否会导致 zip 文件显示在对话框中?
  • 嘿,感谢您的评论-是的,我在发布后就想到了这个,并尝试了它,但是这样做,OpenFileDialog 不再向我显示那里的 PDF 文件,虽然它现在确实显示了该位置的 ZIP 文件夹。我已经更新了我的 OP,以反映我尝试这样做时遇到的问题。
  • 在你的第一个例子中你有OFDlg.DefaultExt = ".pdf|.zip";。那是一个错误。 DefaultExt 需要一个扩展名:第一次显示对话框时默认使用的扩展名。它应该是“.pdf”或“.zip”。访问冲突可能是因为您试图打开一个 .zip 文件,就好像它是 PDF 一样。这不会有好的结局。
  • 您可以在一行中添加所有过滤器(PDF 和 ZIP)。您还有一个属性来设置默认文件类型和选择的初始过滤器索引。
  • 听起来您想知道如何打开 ZIP 文件以获取其中的 PDF 文件。

标签: c# wpf pdf encryption openfiledialog


【解决方案1】:

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

通常还会添加“所有文件”选项(以 . 作为搜索模式)。这样,如果用户想要打开的文件类型在列表中不可用,他们无论如何都可以看到它。

至于打开 zip 文件中的 PDF 文件,您需要自己提取 PDF 文件。 This question 有一些选项可以做到这一点。

【讨论】:

    【解决方案2】:

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

    • 仅在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
     }
    

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

    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);
    }
    

    【讨论】:

    • 感谢您的回答博卢。我有与此非常相似的代码,但是在调试它时,当它到达PdfPanel.OpenFile(ExtractedPDF); 行并尝试执行该行时,我收到一个异常消息:FileNotFoundException was unhandled... 下面的消息说:@ 987654327@...MoonPDF 是我用来在 GUI 面板上显示 PDF 文件的库...
    • 您是否检查过您的本地驱动器上是否存在ExtractedPDF?如果它来自一个 zip 文件,它将位于一个临时文件夹中(例如 C:\Users\username\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\zxczcxxx\xxx.pdf)。
    • 我刚刚更新了我的 OP-我认为问题在于 ExtractedPDF 保存了包含 PDF 的文件夹的路径/名称,而不是 PDF 本身-有没有办法可以获取该文件夹中的 PDF,以便我可以将其名称传递给变量?
    • PDF 文件确实存在于我的本地驱动器上——因为我已成功解压缩它。
    • 我不知道你可以通过设置 InitialDirectory 让 OpenFileDialog 进入 zip 文件。这为我节省了很多工作,谢谢。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2010-11-21
      • 1970-01-01
      • 2013-09-14
      • 1970-01-01
      • 2014-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多