S-JIS[2007-02-11/2022-03-25] 変更履歴
Javaでは、リソース(プロパティーファイル)を扱う方法が用意されている。
リソースとは、実行時に使用する(classファイル以外の)データのこと。プロパティーファイルや画像ファイルなど。
プロパティーファイルとは、「キー=値」という形式で定数値を保持しているファイルのこと。 (Windowsのiniファイルのようなもの)
|
リソースは、classファイルと同じ場所に置いてあるのが前提。
Eclipse3の場合、ソースディレクトリの下に“拡張子java以外のファイル”を書き込むと、自動的にclassの出力先のディレクトリにコピーしてくれる。
通常のクラスディレクトリーに置いてあるリソースファイルも、jarファイル化した際のjarファイル内に置かれたリソースファイルも、読み込むことが出来る。
プログラムからリソースを読み込む場合、リソースファイルの場所は、絶対位置で指定するか、クラスファイルからの相対位置で指定する。
相対位置指定では、自分より下のディレクトリ(サブディレクトリ)にあるファイルを使用できる。
「..
」を使うことによって相対位置で自分より上にあるディレクトリも指定できるが、通常のファイルの場合でしか読み込めない。すなわち、jarファイル内のファイルは読み込めない。
リソースの指定例 | 説明 |
---|---|
test.jpg |
自分のクラスと同じディレクトリに在るリソース |
res/test.jpg |
自分のクラスと同じ場所のresディレクトリの中に在るリソース |
../test.jpg |
自分の1つ上のディレクトリに在るリソース(jarファイルでは使えない) |
/jp/hishidama/sample/res/test.jpg |
絶対位置指定 |
public void printTextResource() throws Exception { Class c = this.getClass(); ←このクラスの位置からの相対パスを指定 URL url = c.getResource("resource.txt"); InputStream is = url.openStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); while (br.ready()) { System.out.println(br.readLine()); } br.close(); is.close(); }
リソースファイルをInputStreamとして取得できるので、後はリソースファイルの種類に応じて必要なメソッドを呼び出せばよい。
※本来はclose()はfinallyの中で行うべきだが、この例では端折っている。
InputStreamの取得の部分は、以下のように書くことも出来る。
InputStream is = c.getResourceAsStream("resource.txt");
プロパティーは、PropertiesクラスやResourceBundleクラスで扱う。[/2007-12-07]
いずれも、キーを指定して値を取得したりセットしたりする。
違いは、リソースバンドルはユーザー向けに表示する為の文言(言葉)を扱うプロパティーだということ。つまり、対象となる環境(使用国・言語)に応じていくつかプロパティーファイルを用意しておけば、実行時には環境に合ったプロパティーファイルが読み込まれる。
public void printTextProperty() throws Exception { Class c = this.getClass(); InputStream is = c.getResourceAsStream("property.txt"); try { Properties p = new Properties(); p.load(is); } finally { is.close(); } for (Iterator i = p.keySet().iterator(); i.hasNext();) { String key = (String) i.next(); String val = p.getProperty(key); System.out.println(key + "=" + val); } }プロパティーファイルは、1つのプロパティーにつき1行で、「キー=値」という形式で書いていく。[2007-12-13]
リソースバンドルの場合、ファイル名の指定の仕方は少し特殊になる。
絶対パスのみ指定可能で、一番先頭の「/」は取り除き、途中の「/」は「.
」に置き換え、拡張子は省略する(拡張子propertiesのファイルのみ読み込み可能)。
要するに、クラスをパッケージ名つきで表現した(FQCN)のと同じ形式。
/jp/hishidama/sample/res/test.properties
↓
jp.hishidama.sample.res.test
public void printResourceBundle() { ResourceBundle rb = ResourceBundle.getBundle("jp.hishidama.sample.res.test"); for (Enumeration e = rb.getKeys(); e.hasMoreElements();) { String key = (String) e.nextElement(); String val = rb.getString(key); System.out.println(key + "=" + val); } }
[2007-12-07]
リソースバンドルでは、まず、実行環境の地域情報(ロカール)を取得する。getBundle()でロカールを指定しない場合、デフォルトロカール(Locale#getDefault())
が使われる。
デフォルトロカールは、システムプロパティーのuser.language(日本ならja)、user.country(日本ならJP)、user.variant(日本なら空文字列)を使って生成される。
日本の場合は「ja_JP」になる。
実行環境が日本の場合、まず、ファイル名に「_ja_JP」が付いたプロパティーファイルがあればそれを読み込む。
無い場合、ファイル名に「_ja」が付いたプロパティーファイルがあればそれを読み込む。
(ja_JPやjaは、大文字でも小文字でも可能)
それも無ければ、ファイル名そのもののプロパティーファイルを読み込む。
各ファイル内に同一のキーがある場合、先に読み込んだファイルに書かれている内容が優先される。
したがって、例えばja_JP付きのファイルに日本語を書いておき、何も付いていないファイルに英語を書いておくとかという使い方をする。
で、さらにfr_FRとかko_KRとか、別の言語のファイルを用意しておくわけだ。
ただしリソースバンドルは英語以外のエンコードに対応していないので、プロパティーファイルはnative2ascii等で変換しておく必要がある。
プロパティーファイル | 値の取得 | 取得できる値 | ||
---|---|---|---|---|
test_ja_jp .properties |
test_ja .properties |
test .properties |
rb = ResourceBundle. |
|
key1=abc | key1=xxx | key1=123 | rb.getString("key1") |
abc |
key2=yyy | key2=456 | rb.getString("key2") |
yyy | |
key3=789 | rb.getString("key3") |
789 |
参考: ITproのResourceBundleの新機能
… リソースバンドルではファイルの代わりにクラスが指定できるとか、もっと高機能らしい
クラスが指定できるもんだから、プロパティーファイル名の指定方法がFQCNと同じだったんだね〜。
取得したプロパティー(リソースバンドル)は、以下のようなメソッドで操作できる。
操作 | Properties p | ResourceBundle rb |
---|---|---|
値の取得 | String val = p.getProperty(key); |
String val = rb.getString(key); |
値の設定 | p.setProperty(key,val); |
|
キーの一覧を取得 | Set set = p.keySet(); |
Enumeration e = rb.getKeys(); |
キーと値の一覧を表示 | p.list(System.out); |
|
キーと値をファイル出力 | os = new FileOutputStream("ファイル名"); |
キーや値に日本語を使用したプロパティーファイルを読み込むと、文字化けする。
上記の読み込み方法では、ASCII文字にしか対応していない。
(Eclipse3.2の場合(デフォルトでは)、拡張子がpropertiesのファイルに日本語を書き込むと、エラーになってファイルを保存できない)
こういうときの為にnative2asciiというツールがある。
これは、日本語をプロパティー(リソースバンドル)クラスで読み込めるような形式に変換してくれる。(日本語の文字を「\uxxxx」という形式の文字列に変換する)
antにnative2asciiというタスクがあるので、それを使うのが一般的。つまり、プログラムの実行前にantを実行して
プロパティーファイルを変換しておく。
Eclipseの場合、そういう変換を自動的にやってくれるプラグインがあるので、それを使うのもいいかも。
しかし、JDK1.6のPropertiesの場合は もっとエレガントな解決方法がある。
上記の方法ではProperties#load(InputStream)を使用したが、新設されたProperties#load(Reader)を使用すればよい。
InputStreamからReaderを作ってエンコードを指定するだけ。(エンコードはデフォルトのままでもたぶんOK)
日本語もそのまま使えるし、今までの形式の「\uxxxx」も使える。
保存の為のstore()にも、同じくWriterを引数にとるメソッドが追加されている。
もっと早くこうしてくれればよかったのに(嘆)
(プロパティーファイルではないが、)JavaVMの実行時に設定されるシステムプロパティーがある。[2007-06-28]
どのようなシステムプロパティーが存在するかは、SystemクラスのJavadocに載っている。
Javaコマンドでシステムプロパティー一覧を表示できる。[2022-03-25]
> java -XshowSettings:properties -version
参考:nowokayさんのJava 18新機能まとめ
システムプロパティーをStringで取得する方法の他、booleanやIntegerで取得する方法が用意されている。[2009-12-31]
(とは言っても、なぜBooleanやIntegerクラスにあるのか…getBoolean()とかparseBoolean()とか、紛らわしい)
型 | 取得方法 | 概要 | 備考 |
---|---|---|---|
String | String value = System.getProperty("キー"); |
Properties p = System.getProperties(); |
無い場合はnull |
String value = System.getProperty("キー", "デフォルト値"); |
Properties p = System.getProperties(); |
||
Properties p = System.getProperties(); |
Hashtable#get("キー") |
無い場合や Stringでない場合はnull | |
Properties p = System.getProperties(); |
|||
boolean | boolean value = Boolean.getBoolean("キー"); |
String s = System.getProperty("キー"); |
無い場合や 解釈できない場合はfalse |
Integer | Integer value = Integer.getInteger("キー"); |
String s = System.getProperty("キー"); |
無い場合や 数値でない場合はnull |
Integer value = Integer.getInteger("キー", デフォルト値); |
|||
Long | Long value = Long.getLong("キー"); |
String s = System.getProperty("キー"); |
無い場合や 数値でない場合はnull |
Long value = Long.getLong("キー", デフォルト値); |
System.getProperties().list(System.out);
※値が長すぎる場合、その値は途中で切られるので注意
Properties p = System.getProperties(); for (Object key : p.keySet()) { ←キーはオブジェクト型 //String val = p.getProperty((String) key); //Object val = p.get(key); String val = System.getProperty((String) key); System.out.println(key + "=" + val); }
System#getProperty()は、セキュリティーがチェックされる(セキュリティーチェックが有効の場合)。
Properties#getProperty()はチェックされない。
システムプロパティーは、setProperty()で設定することが出来る。[2009-12-23]
System.setProperty("キー", "値");
ただし、値にnullを指定することは出来ない。(指定するとNullPointerExceptionが発生する)
nullにしたい場合は、プロパティーを削除することで代用する。
System.getProperties().remove("キー"); //JDK1.4 System.clearProperty("キー"); //JDK1.5以降
システムプロパティーは、javaコマンドの実行時に-Dオプションを付けることで自由に指定することが出来る。[2008-07-30]
>java -Dtest=テスト -Dhoge=ほげ jp.hishidama.prop.Sample
jp/hishidama/prop/Sample.java:
package jp.hishidama.prop; public class Sample { public static void main(String[] args) { System.out.println(System.getProperty("test")); System.out.println(System.getProperty("hoge")); } }
(プロパティーでも何でも無いが、)JDK1.5以降では、JavaVM実行時の環境変数を取得する事が出来る。[2008-07-30]
→Windowsの環境変数・UNIXの環境変数
全環境変数を出力する例:
System.out.println(System.getenv()); // Map<String, String> env = System.getenv();
指定した環境変数を取得する例:
String path = System.getenv("PATH");
System#getenv(String)は、JDK1.4では非推奨メソッドであり、内部も実装されていなかった。
(呼び出すとjava.lang.Error(getenv no longer supported, use properties and -D instead(getenvはサポートしてねーから、-Dを指定してプロパティーを使えや))が発生する)
環境変数PATHに関してはSystem.getProperty("java.library.path")で代用して取得できるが、
その他のものに関しては 自分でjavaコマンドのオプション-Dを使って値を指定してSystem#getProperty()で取得してやらないといけない。
プロパティー | 環境変数 | 備考 | |
---|---|---|---|
Windows | UNIX | ||
java.home | JAVA_HOME | JAVA_HOME | |
java.class.path | CLASSPATH | CLASSPATH | |
java.library.path | PATH | PATH LD_LIBRARY_PATH |
|
user.dir | CD | PWD | |
user.name | USERNAME | USER | |
user.home | USERPROFILE (HOMEDRIVE HOMEPATH) |
HOME | WindowsXPの場合、「C:\Documents and Settings\ユーザー名」 |
java.io.tmpdir | TMPまたはTEMP (TMPが優先) |
→テンポラリーファイル作成 |
でも要望が強かった為か、JDK1.5以降ではgetenv()は非推奨メソッドでなくなり、ちゃんと使えるようになった。
(今のところ唯一、非推奨になったけど非推奨でなくなった例らしい)