質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JAR

JAR(又はJava ARchive)はコンパイルされた複数のJavaバイトコード及び関連ファイルのリソースを一つのファイルに統合したものです。JARファイルはZIPファイルのフォーマットで構築されています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

7450閲覧

jarファイル内のプロパティファイルを参照する方法について

H-T

総合スコア4

JAR

JAR(又はJava ARchive)はコンパイルされた複数のJavaバイトコード及び関連ファイルのリソースを一つのファイルに統合したものです。JARファイルはZIPファイルのフォーマットで構築されています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2021/07/06 17:18

編集2021/07/07 15:42

前提・実現したいこと

jarファイル内に存在するプロパティファイルの読み込みを行いたいです。

発生している問題・エラーメッセージ

ソースを実行するとプロパティファイルに記述されている内容の出力を行えるのですがjarファイルで実行するとFileNotFoundExceptionとファイルが見つからないと言われてしまいます。
下記のソースをどう修正したら良いでしょうか。

エラーメッセージ

java.io.FileNotFoundException: property/test.property (No such file or directory) at java.base/java.io.FileInputStream.open0(Native Method) at java.base/java.io.FileInputStream.open(FileInputStream.java:211) at java.base/java.io.FileInputStream.<init>(FileInputStream.java:153) at java.base/java.io.FileInputStream.<init>(FileInputStream.java:108) at util.PropertyUtil.getProperty(PropertyUtil.java:24) at service.TestReadJarService.outputYear(TestReadJarService.java:20) at service.TestReadJarService.Controller(TestReadJarService.java:12) at service.TestReadJarService.<init>(TestReadJarService.java:8) at main.Main.main(Main.java:8)

Main.java

package main; import service.TestReadJarService; public class Main { public static void main(String[] args) { new TestReadJarService(); } }

TestReadJarService.java

package service; import util.PropertyUtil; public class TestReadJarService { final String PROPERTY_FILE = "test.property"; public TestReadJarService() { Controller() ; } private void Controller() { outputName(); outputYear(); } private void outputName() { String name = new PropertyUtil().getProperty(PROPERTY_FILE,"Name"); System.out.println(name); } private void outputYear() { String year = new PropertyUtil().getProperty(PROPERTY_FILE,"Year"); System.out.println(year); } }

PropertyUtil.java

package util; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class PropertyUtil { public String getProperty(String fileName, String key) { Properties properties = new Properties(); String path = getPath(fileName); try (InputStream property = new FileInputStream(path)) { properties.load(property); return properties.getProperty(key); } catch (IOException e) { return "failed"; } } private String getPath(String fileName) { String path = "property/" + fileName; return path; } }

test.property

Name=TAROU Year=10

パッケージ構成

ReadJar(プロジェクト名) -.classpath -.project -.settings -src -main -Main.java -service -TestReadJarService.java -util -PropertyUtil.java -bin -main -Main.class -service -TestReadJarService.class -util -PropertyUtil.class -property -test.property

jarの中身
-test.property

META-INF/MANIFEST.MF .classpath main/Main.class service/TestReadJarService.class util/PropertyUtil.class property/test.property .project

★実現したソース★

修正対象 TestReadJarService.java PropertyUtil.java test.properties(test.propertyからファイル名変更) property/test.properties(フォルダ構成変更)

TestReadJarService.java

package service; import util.PropertyUtil; public class TestReadJarService { // パス修正 final String PROPERTY_FILE = "property/test.properties"; public TestReadJarService() { Controller(); } private void Controller() { outputName(); outputYear(); // 追加処理 callJar(); } private void outputName() { String name = new PropertyUtil().getProperty(PROPERTY_FILE,"Name"); System.out.println(name); } private void outputYear() { String year = new PropertyUtil().getProperty(PROPERTY_FILE,"Year"); System.out.println(year); } // 追加メソッド private void callJar() { String gender = new PropertyUtil().getPropertyJar(PROPERTY_FILE,"Gender"); System.out.println(gender); } }

PropertyUtil.java

package util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.Properties; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class PropertyUtil { public String getProperty(String fileName, String key) { Properties properties = new Properties(); String path = getPath(fileName); try (InputStream property = new FileInputStream(path)) { properties.load(property); return properties.getProperty(key); } catch (IOException e) { e.printStackTrace(); return "failed"; } } // 修正あり private String getPath(String fileName) { ClassLoader classLoader = PropertyUtil.class.getClassLoader(); URL url = classLoader.getResource(fileName); return url.getPath(); } // 追加メソッド public String getPropertyJar(String fileName,String key) { ClassLoader classLoader = PropertyUtil.class.getClassLoader(); URL url = classLoader.getResource(fileName); // 絶対パスの取得 // jarで実行した際のurlが「file:/xxx/yyy/...Test.jar!/property/test.properties」 // のようなurlになるためfile:やTest.jar!の!以降を取り除きたい(/xxx/yyy/...Test.jar のようにしたい) String[] s = url.getPath().split(":"); String path = s[s.length - 1].split("!")[0]; File file = new File(path); Properties properties = new Properties(); try (JarFile jarFile = new JarFile(file);) { Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); // jarに固められているクラスファイルやプロパティファイルを1件ずつ取得 String entryFileName = entry.getName(); //System.out.println("entryFileName="+entryFileName); if (entryFileName != null && entryFileName.startsWith(fileName)) { // 取得したファイル名と読み込む対象の名が一致した場合 try (InputStream property = classLoader.getResourceAsStream(entryFileName);) { properties.load(property); } } } return properties.getProperty(key); } catch (IOException ex) { // 例外処理 return "Failed"; } } }

test.properties

Name=TAROU Year=10 #追加 Gender=BOY

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

FileInputStreamではファイルの中のファイルを読むことはできません。
クラスパスの通った場所にあるリソース(ファイル)を読む場合、getResourceAsStream('/property/test.property')を使うとよいかもしれません。
Jarのなかのファイルはクラスパスが通っているため参照することができます。

https://ksino.hatenablog.com/entry/2016/03/23/221813

投稿2021/07/06 17:32

編集2021/07/07 00:30
fukasawah

総合スコア147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shiketa

2021/07/06 23:40

> Jarのなかのファイルを読む場合 と限定してしまうと、jarファイルにする前はどうするんだよ、と悩んでしまうかもしれません。 https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Class.html#getResourceAsStream-java.lang.String- > 指定されたクラスに関連したリソースを検索するルールは、クラスのクラス・ローダーを定義して実装されます。 クラスパスの通った場所にあるリソース(ファイル)を、ですかね。
fukasawah

2021/07/07 00:27

御尤もです。JARに限った話ではないですね。修正します
shiketa

2021/07/07 23:46

``` ClassLoader classLoader = Main.class.getClassLoader(); URL url = classLoader.getResource(MESSAGES_DIR); ``` 間違っちゃいないのでしょうが、この書き方のほうが一般的かとおもう。 ``` final URL url = Main.class.getResource(MESSAGES_DIR); ```
shiketa

2021/07/07 23:49

``` String[] fileNames = dir.list(); for (String fileName : fileNames) { try (InputStream is = classLoader.getResourceAsStream(MESSAGES_DIR + fileName);) { ``` 間違っちゃいないのでしょうが、こうでいいとおもう。 ``` for (FilefileName : dir.listFiles()) { try (InputStream is = new FileInputStream(new File(dir, fileName));) { ```
Luice

2021/07/08 00:17

fukasawahさんが指定したようにフルパッケージ指定の場合は問題ありませんが、 リソースの指定方法によっては、class.getResource()とclassLoader.getResource()では 走行するパスが異なるので使い分けが必要になるケースがあります。 https://fumidzuki.com/knowledge/1281/
fukasawah

2021/07/08 01:32

私がBlogのURLを出したのが良くなかったと思いますが、 Blogでやっているのは「ある場所のプロパティファイルを全て読み取る」という事をやっています。もしJarファイルの場合は、JarFileクラスを使って中身を1つづつ読み取るということをやっています。 (もしJarの中にある別のJarが持つプロパティファイルを読みたい、といった場合は似たようなことをやらないといけないかもしれません。) getPropertyJarは、Jarの場合はBlogのやり方に倣ってJarを展開して目当てのPropertiesファイルをクラスローダから読み取る、ということをやっていますが、「Jarの場合はBlogのやり方に倣ってJarを展開して」という処理が不要かと思います。 今回はもっと単純で対象のプロパティファイル名が分かっていてそれを読みたいだけかと思うので、以下のようにすれば動くと思います。次のコードはそのまま実行しても、JAR化して `java -jar my.jar` で実行しても同じように動くはずです。 ``` public class PropertyUtil { public String getProperty(String fileName, String key) { Properties properties = new Properties(); String path = getPath(fileName); try (InputStream property = PropertyUtil.class.getResourceAsStream(path)) { properties.load(property); return properties.getProperty(key); } catch (IOException e) { return "failed"; } } private String getPath(String fileName) { String path = "/property/" + fileName; // 先頭に / をつけて絶対pathで指定する return path; } } ``` あと細かいですが、 PropertyUtil.class.getResourceAsStream('...'),と PropertyUtil.class.getClassLoader().getResourceAsStream('...')では若干振る舞いが違います。(後者のClassLoaderのgetResourceAsStreamは先頭の/を絶対Pathのように扱えないなど。) そこはドキュメントをみるか、コードで書いて試してみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問