私はマルチモジュールJavaプロジェクトに取り組んでいます。これは、相互に依存するEclipseの複数のプロジェクトで構成されています。GUIテーマのサポートを追加するために、コードを含まず、必要なアイコンと画像のみを含むJavaプロジェクトを作成しました。 GUI、私はそれをJavaプロジェクトにしたので、Mavenはそれを.jarにビルドします。これで、複数のプロジェクトをメインGUIにロードするメインアプリケーションができました。メインGUIは、現時点で実際のモジュール内のリソースからアイコンを取得します。私がやりたいのは、メインアプリケーションの.jarのクラスパスに含まれている外部ダミー.jarからこれらすべてのリソースをロードすることです。私がこれまでに見つけたすべての方法がうまくいくようには見えません。.jarには実際のjava.classesが含まれていないため、参照するClassLoaderはありません。.jarを抽出せずに画像をロードする他の方法はありますか?
3 に答える
外部jarファイルをzipアーカイブとして扱い、次のような画像/リソースを読み取ります。
public ZipStuff(String filename) throws IOException
{
ZipFile zf = new ZipFile(filename);
Enumeration<? extends ZipEntry> entries = zf.entries();
while (entries.hasMoreElements()) {
ZipEntry ze = entries.nextElement();
ImageIcon ii = new ImageIcon(ImageIO.read(zf.getInputStream(ze)));
JLabel l = new JLabel(ii);
getContentPane().add(l);
}
setVisible(true);
pack();
}
この場合、JLabelにロードする単一の画像を含むjarファイルがあります。ZipStuffクラスはJFrameです。
すべてのリソースを取得できます (クラスパス上のすべての jar ファイルは、クラスがなくても機能するはずです)。
Enumeration<URL> resources = null;
try {
resources = Thread.currentThread().getContextClassLoader().getResources(someResource);
} catch (Exception ex) {
//no op
}
if (resources == null || !resources.hasMoreElements()) {
resources = ClasspathReader.class.getClassLoader().getResources(someResource);
}
次に、現在のリソースがファイルかどうかを確認します。ファイルとして直接扱えるファイル。しかし、あなたの質問はjarファイルに関するものだったので、そこには行きません。
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
if (resource.getProtocol().equals("file")) {
//if it is a file then we can handle it the normal way.
handleFile(resource, namespace);
continue;
}
この時点では、jar:file リソースしかないはずなので... 次のように文字列を分割します。
jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/
これに
/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar
この
/組織/ノード/
厄介なエラーチェックなしで上記を実行するコードを次に示します。:)
String[] split = resource.toString().split(":");
String[] split2 = split[2].split("!");
String zipFileName = split2[0];
String sresource = split2[1];
System.out.printf("After split zip file name = %s," +
" \nresource in zip %s \n", zipFileName, sresource);
これで、zip ファイル名が得られたので、それを読み取ることができます。
ZipFile zipFile = new ZipFile(zipFileName);
これで、そのエントリを反復処理できます。
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
/* If it is a directory, then skip it. */
if (entry.isDirectory()) {
continue;
}
String entryName = entry.getName();
System.out.printf("zip entry name %s \n", entryName);
探しているリソースで始まるかどうかを確認します。
if (!entryName.startsWith(someResource)) {
continue;
}
ディレクトリであるかどうかを確認するために、以前に行った2つのトリックがありました
boolean isDir = !someResource.endsWith(".txt");
これは、.txt で終わるリソースを探しているためにのみ機能し、.txt で終わらない場合は、ディレクトリ /foo/dir と /foo/dir/ の両方が機能すると想定します。
他のトリックはこれでした:
if (someResource.startsWith("/")) {
someResource = someResource.substring(1);
}
クラスパス リソースは、開始スラッシュで実際に開始することはできません。論理的にはそうですが、実際にはそれを取り除く必要があります。これは、クラスパス リソースの既知の動作です。リソースがjarファイルにない限り、スラッシュで機能します。要するに、それを取り除くことで、常に機能します。
いまいましいものの実際のファイル名を取得する必要があります。エントリ名の fileName 部分。ここで、/foo/bar/foo/bee/bar.txt であり、必要なファイル名は「bar.txt」です。while ループの内部に戻ります。
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
...
String entryName = entry.getName(); //entry is zipEntry
String fileName = entryName.substring(entryName.lastIndexOf("/") + 1);
/** See if the file starts with our namespace and ends with our extension. */
if (fileName.startsWith(namespace) && fileName.endsWith(".txt")) {
次に、これらのエントリが基準に一致するかどうかを確認し、一致する場合はファイルの内容を System.out に読み取ります。
try (Reader reader = new InputStreamReader(zipFile.getInputStream(entry))) {
StringBuilder builder = new StringBuilder();
int ch = 0;
while ((ch = reader.read()) != -1) {
builder.append((char) ch);
}
System.out.printf("zip fileName = %s\n\n####\n contents of file %s\n###\n",
entryName, builder);
} catch (Exception ex) {
ex.printStackTrace();//it is an example/proto :)
}
}
ここで完全な例を見ることができます: Sleepless in Pleasanton。
あなたが試すかもしれない3つのこと:
- ClassLoader 参照を取得するために使用できるダミー クラスをリソース jar に作成します。
- jar ファイルが存在する場所がわかっている場合は、URLClassLoader を使用します。
- を拡張して独自の ClassLoader を作成する可能性は常にあります
java.lang.ClassLoader
。