使用桌面默认应用程序打开存储在JAR文件中的PDF文件

4

我即将完成计算机科学课程的程序开发。然而,其中一个要求是在应用程序中拥有用户手册。我将用户手册保存为PDF文件,并存储在Eclipse的工作区中。

它存储在“/Documents/PDF Manual.pdf”下。我最初使用了以下代码:

URL url = getClass().getResource( fileSeparator + "Documents" + fileSeparator + "PDF Manual.pdf");
           //fileSeparator = '/' on mac, & '\\' on windows
        File userManual = new File (url.toURI());
        if (userManual.exists())
        {
            Desktop.getDesktop().open(userManual);
        }

在从eclipse运行项目时,这个方法可以正常工作,但是当程序被导出为jar文件时,URI会返回一个非层次结构的异常(如预期所示)。我想通过使用substring和replaceAll()来玩弄url.toString()以去除不需要的字符(%20代表空格),然而这样会得到奇怪的结果,并且当它不是jar文件时代码将无法正常工作。
我尝试使用InputStream,但这只用于从文件中读取数据,而我不能使用桌面应用程序打开该文件。
由于提交过程的原因,PDF必须保存在项目文件夹内。
此外,我的代码必须是平台独立的(或者至少在Windows和Mac上工作),因此操纵文件名变得更加复杂。有什么建议吗?
编辑:
在@SubOptimal的帮助下,我现在正在使用以下代码:
String inputPdf = "Documents" + fileSeparator + "PDF Manual.pdf";
        InputStream manualAsStream = getClass().getClassLoader().getResourceAsStream(inputPdf);

        Path tempOutput = Files.createTempFile("TempManual", ".pdf");
        tempOutput.toFile().deleteOnExit();

        Files.copy(manualAsStream, tempOutput, StandardCopyOption.REPLACE_EXISTING);

        File userManual = new File (tempOutput.toFile().getPath());
        if (userManual.exists())
        {
            Desktop.getDesktop().open(userManual);
        }

这在mac上可行。然而,在Windows上,由于某些未知原因,manualAsStream为空。


1
我猜你需要先从JAR文件中提取PDF到一个临时位置(系统属性java.io.tmpdir),因为桌面应用程序可能无法打开存档文件中的文件。 - SubOptimal
@SubOptimal 当使用 url.toURI() 创建新文件时,会返回错误,因此我无法将 PDF 放入临时文件夹中,因为在 JAR 中时根本无法访问其路径。 我的想法是,我需要调用 Files.copy() 将 PDF 放置在临时目录中,这样正确吗? - flynn96
在编辑中的解决方案对我在Windows上也起作用,尽管是5年后。永远不会太晚! - tokyo
2个回答

2
完整的工作示例。在Windows环境下测试过。
文件结构
.\REPL.java
.\doc\manual.pdf
.\manifest.mf

REPL.java

package sub.optimal;

import java.io.InputStream;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.awt.Desktop;

public class REPL {

    public static void main(String[] args) throws Exception {
        String inputPdf = "doc/manual.pdf";
        Path tempOutput = Files.createTempFile("TempManual", ".pdf");
        tempOutput.toFile().deleteOnExit();
        System.out.println("tempOutput: " + tempOutput);
        try (InputStream is = REPL.class.getClassLoader().getResourceAsStream(inputPdf)) {
            Files.copy(is, tempOutput, StandardCopyOption.REPLACE_EXISTING);
        }
        Desktop.getDesktop().open(tempOutput.toFile());
    }
}

manifest.mf

Main-Class: sub.optimal.REPL

编译

javac -d . REPL.java

创建JAR文件

mkdir dist\
jar cvfm dist/REPL.jar MANIFEST.MF sub/optimal/REPL.class doc/manual.pdf

执行JAR文件

cd dist\
java -jar REPL.jar

折腾了一番,但我最终让它工作了!谢谢!实际上,我必须指定从“文档”文件夹开始的路径才能获取PDF手册,否则'InputStream'将为空。不过,通过.open()很容易让它工作。谢谢!! - flynn96
经过进一步测试,由于某些原因,该代码在Windows上无法正常工作。我所有关于文件保存的其他代码都遵循保存逻辑,但是这个代码不会打开PDF文件。据我所知,它甚至没有创建临时文件。输入流似乎最终为空。起初我在Mac上也遇到了类似的问题,但是我通过更改文件路径来解决了这个问题。但是在Windows上这种方法行不通。 - flynn96
好的,现在它可以在Mac和Windows上运行了。我追踪到问题出在使用我的fileSeparator变量上(对于Windows是\)。我不知道你可以在基于Windows的文件系统中使用类Unix的表示法。感谢您的帮助!我很感激。 - flynn96

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接