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

时间:2014-11-19 06:34:44

标签: java maven jar javamail filenotfoundexception

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

我有一个小型天气应用,可以生成并发送HTML电子邮件。使用下面的代码,当我从Eclipse运行它时,一切正常。我的电子邮件已生成,它可以访问我的图片资源,并通过附带的附件发送电子邮件。

但是,当我通过运行 mvn install 构建可执行jar并使用 java -jar NameOfMyJar.jar 运行jar时,我得到 java.io.FileNotFound 我的图片资源的例外情况。

我知道我必须对我访问图像资源的方式做错了,我只是不明白为什么它没有打包时工作正常,但每当炸弹时都会爆炸我将它打包成一个罐子。

非常感谢任何建议。


我的项目布局 enter image description here


我如何访问我的图片资源

//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

4 个答案:

答案 0 :(得分: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,来自InputStream Constructed(正如Bill Shannon所说,这是不正确的)。正如他在下面的评论中提到的那样

“您也可以使用”

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

答案 1 :(得分:2)

您无法将JAR文件中的资源作为文件访问,只能将其作为InputStream读取:getResourceAsStream()

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

答案 2 :(得分:1)

试试这个

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

答案 3 :(得分:0)

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

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

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

这是我的代码示例:

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

    }
}

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