无法在可执行文件中访问资源

问题描述 投票:7回答:4

有人可以指出我在这里做错了什么。

我有一个小天气应用程序,生成并发送HTML电子邮件。使用下面的代码,当我从Eclipse运行它时,一切正常。我的电子邮件生成后,它可以访问我的图像资源,并发送包含附件的电子邮件。

但是,当我通过运行mvn install构建可执行jar并使用java -jar NameOfMyJar.jar运行jar时,我的图像资源获得了java.io.FileNotFound异常。

我知道我必须对我如何访问我的图像资源做错了,我只是不明白为什么它在没有打包的情况下工作正常,但每当我将它打包到jar中时都会爆炸。

任何建议都非常感谢。


我的项目布局


我如何访问我的图像资源

//Setup the ATTACHMENTS
        MimeBodyPart attachmentsPart = new MimeBodyPart();
        try {
            attachmentsPart.attachFile("resources/Cloudy_Day.png");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   

StackTrace

    Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: IOException while sending message;
  nested exception is:
    java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
    at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:139)
    at Utilities.SendEmailUsingGmailSMTP.SendWeatherEmail(SendEmailUsingGmailSMTP.java:66)
    at Weather.Main.start(Main.java:43)
    at Weather.Main.main(Main.java:23)
Caused by: javax.mail.MessagingException: IOException while sending message;
  nested exception is:
    java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1167)
    at javax.mail.Transport.send0(Transport.java:195)
    at javax.mail.Transport.send(Transport.java:124)
    at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:134)
    ... 3 more
Caused by: java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:146)
    at javax.activation.FileDataSource.getInputStream(FileDataSource.java:97)
    at javax.activation.DataHandler.writeTo(DataHandler.java:305)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:865)
    at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:462)
    at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:103)
    at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889)
    at javax.activation.DataHandler.writeTo(DataHandler.java:317)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
    at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1773)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)
    ... 6 more
java maven jar javamail filenotfoundexception
4个回答
8
投票

其他人使用getResourceAsStream是正确的,但路径有点棘手。你在resources文件夹中看到小包装图标?这表示resource文件夹中的所有文件都将放入类路径的根目录中。就像src/main/java中的所有包都放在根目录中一样。所以你会从路径中取出resources

InputStream is = getClass().getResourceAsStream("/Cloudy_Day.png");

抛开:Maven有一个文件结构约定。类路径资源通常放入src/main/resources。如果你在resources中创建一个src/main目录,那么Eclipse应该会自动拾取它,并为你应该在项目浏览器中看到的路径src/main/resource创建一个小包图标。这些文件也将转到root,并且可以以相同的方式访问。我会修复文件结构以遵循此约定。

注意:一个MimeBodyPart,可以是来自ConstructedInputStream (正如Bill Shannon所说,这是不正确的)。如下面的评论中所述

“你也可以使用”附加数据“

mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(
          this.getClass().getResourceAsStream("/Cloudy_Day.png", "image/png"))));

2
投票

您不能将JAR文件中的资源作为File访问,只能将它们作为InputStream读取:getResourceAsStream()

由于MimeBodyPart没有用于InputStream的attach()方法,最简单的方法应该是读取资源并将其写入临时文件,然后附加这些文件。


1
投票

试试这个

new MimeBodyPart().attachFile(new File(this.getClass().getClassLoader().getResource("resources/Cloudy_Day.png").toURI());

0
投票

我不知道这是否会对任何人有所帮助。但是,我有一个与OP类似的情况,我通过使用递归函数在类路径中查找文件来解决这个问题。这个想法是这样的,当另一个开发人员决定将资源移动到另一个文件夹/路径时。只要名称仍然相同,它仍然会被发现。

例如,在我的工作中,我们通常将我们的资源放在jar之外,然后我们将所述资源路径添加到我们的类路径中,因此这里资源的类路径将根据它所在的位置而不同。

这就是我的代码开始工作的地方,无论文件放在何处,只要它在类路径中就可以找到。

以下是我的代码实例:

import java.io.File;

public class FindResourcesRecursive {

    public File findConfigFile(String paths, String configFilename) {
        for (String p : paths.split(File.pathSeparator)) {
            File result = findConfigFile(new File(p), configFilename);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

    private File findConfigFile(File path, String configFilename) {
        if (path.isDirectory()) {
            String[] subPaths = path.list();
            if (subPaths == null) {
                return null;
            }
            for (String sp : subPaths) {
                File subPath = new File(path.getAbsoluteFile() + "/" + sp);
                File result = findConfigFile(subPath, configFilename);
                if (result != null && result.getName().equalsIgnoreCase(configFilename)) {
                    return result;
                }
            }
            return null;
        } else {
            File file = path;
            if (file.getName().equalsIgnoreCase(configFilename)) {
                return file;
            }
            return null;
        }
    }

}

这里我有一个测试用例,它与我的test / resources文件夹中的文件“test.txt”相结合。所述文件的内容是:

A sample file

现在,这是我的测试用例:

import org.junit.Test;

import java.io.*;

import static org.junit.Assert.fail;

public class FindResourcesRecursiveTest {

    @Test
    public void testFindFile() {
        // Here in the test resources I have a file "test.txt"
        // Inside it is a string "A sample file"
        // My Unit Test will use the class FindResourcesRecursive to find the file and print out the results.
        File testFile = new FindResourcesRecursive().findConfigFile(
                System.getProperty("java.class.path"),
                "test.txt"
        );

        try (FileInputStream is = new FileInputStream(testFile)) {
            int i;
            while ((i = is.read()) != -1) {
                System.out.print((char) i);
            }
            System.out.println();
        } catch (IOException e) {
            fail();
        }

    }
}

现在,如果您运行此测试,它将打印出“示例文件”,测试将为绿色。

© www.soinside.com 2019 - 2024. All rights reserved.