どのようにリストのファイル内のJARファイルとは何ですか?
-
07-07-2019 - |
質問
私はこのコードを読み取るすべてのファイルからディレクトリです。
File textFolder = new File("text_directory");
File [] texFiles = textFolder.listFiles( new FileFilter() {
public boolean accept( File file ) {
return file.getName().endsWith(".txt");
}
});
です。ので、配列のすべてのファイルの末尾が".txt"からディレクトリ"text_directory".
かの内容を読み込むディレクトリにファッション 以内 JARファイルとは何ですか?
いていきたいと思っておりますが、リスト内の画像が私のJARファイルだったので、負荷として:
ImageIO.read(this.getClass().getResource("CompanyLogo.png"));
この一作品で、"CompanyLogo"は"ハードコード"で画像の数のJARファイルできるから10 200変数の長さです。)
編集
でも私の主な問題にすることはできない。どの 名前のJARファイル 私のメインクラス。
付与えを使ってご覧くださ java.util.Zip
.
私の構造は以下のようになっています:
なんという意味なのでしょ:
my.jar!/Main.class
my.jar!/Aux.class
my.jar!/Other.class
my.jar!/images/image01.png
my.jar!/images/image02a.png
my.jar!/images/imwge034.png
my.jar!/images/imagAe01q.png
my.jar!/META-INF/manifest
まずはできる負荷インスタンス"画像/image01.png"を用い:
ImageIO.read(this.getClass().getResource("images/image01.png));
でもだからこそ知っているファイル名にしていま荷しています。
解決
CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
if (src != null) {
URL jar = src.getLocation();
ZipInputStream zip = new ZipInputStream(jar.openStream());
while(true) {
ZipEntry e = zip.getNextEntry();
if (e == null)
break;
String name = e.getName();
if (name.startsWith("path/to/your/dir/")) {
/* Do something with this entry. */
...
}
}
}
else {
/* Fail... */
}
Java 7では、JAR(zip)ファイルから FileSystem
を作成し、NIOのディレクトリウォーキングおよびフィルタリングメカニズムを使用して検索できることに注意してください。これにより、JARと" exploded"を処理するコードを記述しやすくなります。ディレクトリ。
他のヒント
IDEファイルと.jarファイルの両方で機能するコード:
import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
public class ResourceWalker {
public static void main(String[] args) throws URISyntaxException, IOException {
URI uri = ResourceWalker.class.getResource("/resources").toURI();
Path myPath;
if (uri.getScheme().equals("jar")) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
myPath = fileSystem.getPath("/resources");
} else {
myPath = Paths.get(uri);
}
Stream<Path> walk = Files.walk(myPath, 1);
for (Iterator<Path> it = walk.iterator(); it.hasNext();){
System.out.println(it.next());
}
}
}
ericksonの回答は完全に機能しました:
これが作業コードです。
CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
List<String> list = new ArrayList<String>();
if( src != null ) {
URL jar = src.getLocation();
ZipInputStream zip = new ZipInputStream( jar.openStream());
ZipEntry ze = null;
while( ( ze = zip.getNextEntry() ) != null ) {
String entryName = ze.getName();
if( entryName.startsWith("images") && entryName.endsWith(".png") ) {
list.add( entryName );
}
}
}
webimages = list.toArray( new String[ list.size() ] );
そして、これからloadメソッドを修正しました:
File[] webimages = ...
BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex].getName() ));
これへ:
String [] webimages = ...
BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex]));
たいと思い拡acheron55の 答え, であるため、非常に非見~米国食品安全強化法の数理由:
- なり、
FileSystem
オブジェクトです。 - でチェックしない場合
FileSystem
オブジェクトは既に存在しています。 - なスレッドセーフです。
これは幾分安全解
private static ConcurrentMap<String, Object> locks = new ConcurrentHashMap<>();
public void walk(String path) throws Exception {
URI uri = getClass().getResource(path).toURI();
if ("jar".equals(uri.getScheme()) {
safeWalkJar(path, uri);
} else {
Files.walk(Paths.get(path));
}
}
private void safeWalkJar(String path, URI uri) throws Exception {
synchronized (getLock(uri)) {
// this'll close the FileSystem object at the end
try (FileSystem fs = getFileSystem(uri)) {
Files.walk(fs.getPath(path));
}
}
}
private Object getLock(URI uri) {
String fileName = parseFileName(uri);
locks.computeIfAbsent(fileName, s -> new Object());
return locks.get(fileName);
}
private String parseFileName(URI uri) {
String schemeSpecificPart = uri.getSchemeSpecificPart();
return schemeSpecificPart.substring(0, schemeSpecificPart.indexOf("!"));
}
private FileSystem getFileSystem(URI uri) throws IOException {
try {
return FileSystems.getFileSystem(uri);
} catch (FileSystemNotFoundException e) {
return FileSystems.newFileSystem(uri, Collections.<String, String>emptyMap());
}
}
あるイタリアに必要な同期のファイル名こだけでの同期オブジェクトと同じオブジェクト毎時間又は方法 synchronized
では純粋に最適化.
というこれはあくまでも未だに問題解決であるがその他の部品のコードを使用する FileSystem
インターフェイスは、同じファイルであることが確認されている干渉しても単一のネジ付きものとします。
また、チェックしない null
s(例えば、 getClass().getResource()
.
この特定のJava NIOインタフェースのような恐ろしいかについて紹介し、グローバル/シングルトン以外のスレッド-安全な資源、およびドキュメントが極めて曖昧になるかも知れませんが不思議な現象がいろいろありプロバイダ固有の実装).結果が異なる場合がありますその他の FileSystem
プロバイダ(JAR).ん、ありがとうございまのいい理由になっていることとなっているので、わからないませんが研究を実装.
「パッケージですべてのJUnitを実行する」ために書いたメソッドです。ニーズに合わせて調整できる必要があります。
private static void findClassesInJar(List<String> classFiles, String path) throws IOException {
final String[] parts = path.split("\\Q.jar\\\\E");
if (parts.length == 2) {
String jarFilename = parts[0] + ".jar";
String relativePath = parts[1].replace(File.separatorChar, '/');
JarFile jarFile = new JarFile(jarFilename);
final Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
final JarEntry entry = entries.nextElement();
final String entryName = entry.getName();
if (entryName.startsWith(relativePath)) {
classFiles.add(entryName.replace('/', File.separatorChar));
}
}
}
}
編集: ああ、その場合、このスニペットも必要になるかもしれません(同じユースケース:))
private static File findClassesDir(Class<?> clazz) {
try {
String path = clazz.getProtectionDomain().getCodeSource().getLocation().getFile();
final String codeSourcePath = URLDecoder.decode(path, "UTF-8");
final String thisClassPath = new File(codeSourcePath, clazz.getPackage().getName().repalce('.', File.separatorChar));
} catch (UnsupportedEncodingException e) {
throw new AssertionError("impossible", e);
}
}
だから、私の主な問題は、メインクラスが存在するjarの名前をどのように知るかだと思います。
プロジェクトがJarにパックされていると仮定すると(必ずしもtrueではありません!)、ClassLoader.getResource()またはfindResource()をクラス名(.classが後に続く)で使用して、特定のクラスを含むjarを取得できます。返されるURLからjar名を解析する必要があります(それほど難しくはありません)。これは読者の演習として残しておきます:-)
クラスがjarの一部ではない場合は必ずテストしてください。
jarファイルは、構造化されたマニフェストを持つ単なるzipファイルです。通常のJava zipツールを使用してjarファイルを開き、ファイルの内容をそのようにスキャンし、ストリームを膨らませます。それをgetResourceAsStream呼び出しで使用すると、すべてがうまくいきます。
編集/明確化後
すべての断片を思い出すのに1分かかりました、そしてそれを行うためのよりきれいな方法があると確信していますが、私は狂っていないことを確認したかったです。私のプロジェクトでは、image.jpgはメインjarファイルの一部のファイルです。メインクラス(SomeClassがエントリポイント)のクラスローダーを取得し、それを使用してimage.jpgリソースを検出します。次に、このImageInputStreamにそれを取り込むためのストリームマジックがあり、すべてが正常です。
InputStream inputStream = SomeClass.class.getClassLoader().getResourceAsStream("image.jpg");
JPEGImageReaderSpi imageReaderSpi = new JPEGImageReaderSpi();
ImageReader ir = imageReaderSpi.createReaderInstance();
ImageInputStream iis = new MemoryCacheImageInputStream(inputStream);
ir.setInput(iis);
....
ir.read(0); //will hand us a buffered image
された実際のJARファイルできるリストを使用したコンテンツ JarFile.entries()
.お知る必要があるのは、JARファイルができなかのクラスローダを一覧もできます。
対応することができるでしょう仕事には、JARファイルのURLから返される ThisClassName.class.getResource("ThisClassName.class")
, を引き起こす場合もある小さなビットヒ.
しばらく前に、JAR内部からクラスを取得する関数を作成しました:
public static Class[] getClasses(String packageName)
throws ClassNotFoundException{
ArrayList<Class> classes = new ArrayList<Class> ();
packageName = packageName.replaceAll("\\." , "/");
File f = new File(jarName);
if(f.exists()){
try{
JarInputStream jarFile = new JarInputStream(
new FileInputStream (jarName));
JarEntry jarEntry;
while(true) {
jarEntry=jarFile.getNextJarEntry ();
if(jarEntry == null){
break;
}
if((jarEntry.getName ().startsWith (packageName)) &&
(jarEntry.getName ().endsWith (".class")) ) {
classes.add(Class.forName(jarEntry.getName().
replaceAll("/", "\\.").
substring(0, jarEntry.getName().length() - 6)));
}
}
}
catch( Exception e){
e.printStackTrace ();
}
Class[] classesA = new Class[classes.size()];
classes.toArray(classesA);
return classesA;
}else
return null;
}
これは、 Reflections ライブラリを使用して、カップルを追加した正規表現名パターンによってクラスパスを再帰的にスキャンする例です。 グアバのリソースのコンテンツを取得する特典:
Reflections reflections = new Reflections("com.example.package", new ResourcesScanner());
Set<String> paths = reflections.getResources(Pattern.compile(".*\\.template<*>quot;));
Map<String, String> templates = new LinkedHashMap<>();
for (String path : paths) {
log.info("Found " + path);
String templateName = Files.getNameWithoutExtension(path);
URL resource = getClass().getClassLoader().getResource(path);
String text = Resources.toString(resource, StandardCharsets.UTF_8);
templates.put(templateName, text);
}
これは、jarと展開されたクラスの両方で機能します。
acheron55'sを移植しましたJava 7に答え、 FileSystem
オブジェクトを閉じました。このコードは、IDE、jarファイル、Tomcat 7の戦争内のjarで機能します。ただし、JBoss 7のwar内のjarでは動作しないことに注意してください( FileSystemNotFoundException:Provider&quot; vfs&quot; not installed
、この投稿)。さらに、元のコードと同様に、 errr 。これらの理由により、私はこのソリューションを放棄しました。ただし、これらの問題を受け入れることができる場合、私の既製のコードは次のとおりです。
import java.io.IOException;
import java.net.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
public class ResourceWalker {
public static void main(String[] args) throws URISyntaxException, IOException {
URI uri = ResourceWalker.class.getResource("/resources").toURI();
System.out.println("Starting from: " + uri);
try (FileSystem fileSystem = (uri.getScheme().equals("jar") ? FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap()) : null)) {
Path myPath = Paths.get(uri);
Files.walkFileTree(myPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println(file);
return FileVisitResult.CONTINUE;
}
});
}
}
}
JarScanと呼ばれる非常に便利なユーティリティが2つあります:
こちらの質問もご覧ください: JarScan、特定のクラスのすべてのサブフォルダー内のすべてのJARファイルをスキャン
jarのURLからファイルを一覧表示または読み取るための別の方法であり、ネストされたjarに対して再帰的に実行します
https://gist.github.com/trung/2cd90faab7f75b3bcbaa
URL urlResource = Thead.currentThread().getContextClassLoader().getResource("foo");
JarReader.read(urlResource, new InputStreamCallback() {
@Override
public void onFile(String name, InputStream is) throws IOException {
// got file name and content stream
}
});