Jar Dosyamın içinden “Klasör” kaynağını nasıl alabilirim?


139

Projemin kökünde bir kaynak klasörü / paketi var, belirli bir dosyayı yüklemek istemiyorum. Belirli bir dosyayı yüklemek isteseydim, class.getResourceAsStream kullanırdım ve iyi olur! Aslında yapmak istediğim, kaynaklar klasörüne bir "Klasör" yüklemek, bu Klasör içindeki Dosyalara döngü ve her dosyaya bir Akış almak ve içerik okumak ... Çalışma zamanı önce Dosya adlarının belirlenmediğini varsayalım ... Ne yapmalıyım? Jar dosyanızdaki bir Klasör içindeki dosyaların listesini almanın bir yolu var mı? Kaynaklara sahip Jar dosyasının, kodun çalıştırıldığı kavanoz dosyası olduğuna dikkat edin ...

Şimdiden teşekkürler...




5
Birincisi, bir tür-kötü-kötü-kötü durum ise, denemek istediğim son şey olan bir kavanoz dosyasını ayıklamakla ilgili! Dosyaların çıkarılmasını istersem, kurulum zamanında dosyaları kurulum klasörüne koyacağım! Onlara kavanozun içinden erişmek istiyorum ve nedenim, getResourceAsStream bir Dosyaya erişebiliyorsa, Java da ayıklamaya gerek kalmadan bu kavanozdaki klasörleri keşfedebilmelidir! Ama teşekkürler ...
Mostafa Zeinali

Yanıtlar:


111

Sonunda çözümü buldum:

final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());

if(jarFile.isFile()) {  // Run with JAR file
    final JarFile jar = new JarFile(jarFile);
    final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
    while(entries.hasMoreElements()) {
        final String name = entries.nextElement().getName();
        if (name.startsWith(path + "/")) { //filter according to the path
            System.out.println(name);
        }
    }
    jar.close();
} else { // Run with IDE
    final URL url = Launcher.class.getResource("/" + path);
    if (url != null) {
        try {
            final File apps = new File(url.toURI());
            for (File app : apps.listFiles()) {
                System.out.println(app);
            }
        } catch (URISyntaxException ex) {
            // never happens
        }
    }
}

İkinci blok sadece uygulamayı IDE üzerinde çalıştırdığınızda çalışır (jar dosyasıyla değil), bunu beğenmezseniz kaldırabilirsiniz.


Doğru cevap güncellendi. Bu benim yapmak istediğim şey olmasa da, özellikle 34000+ kaynak dosyaları olan bir kodda ... Ama tek çözüm gibi görünüyor. Teşekkür ederim.
Mostafa Zeinali

4
Bilginize, getpath sunucunun etki alanına göre bir şey döndürdüğü için webstart'dan başlatılmışsa bu çalışmaz.
amos

1
Yol bir kavanoza girerse işe yarayacağını düşünmeyin, toURI dönüşümünde bu hatayı verecektir: java.lang.IllegalArgumentException: URI hiyerarşik değil
tribbloid

4
Yalnızca tek kavanoz dosyası için çalışır, başka bir kavanozdaki bağımlılıklardan kaynak çıkarmak için çalışmaz
tribbloid

2
Bu güvenli bir çözüm değildir, çünkü: 1. .jar dosyasının aynı sistemde yerel bir dosya olduğunu varsayar; 2. URL.getPath () geçerli bir dosya adı döndürmez, yalnızca URL'nin yol kısmını döndürür, tüm yüzde kaçmaları korunur; 3. ProtectionDomain.getCodeSource () null değerini döndürebilir .
VGR

14

Takip etmeyi dene.
Kaynak yolunu yapın "<PathRelativeToThisClassFile>/<ResourceDirectory>" Örneğin sınıf yolunuz com.abc.package.MyClass ve resoure dosyalarınız src / com / abc / package / resources /

URL url = MyClass.class.getResource("resources/");
if (url == null) {
     // error - missing folder
} else {
    File dir = new File(url.toURI());
    for (File nextFile : dir.listFiles()) {
        // Do something with nextFile
    }
}

Ayrıca kullanabilirsiniz

URL url = MyClass.class.getResource("/com/abc/package/resources/");

27
Zaman ve çaba için teşekkür ederiz, ancak kodunuz bir .jar dosyasında ve kaynaklarınız da bu .jar Dosyasında olduğunda bu çalışmaz. Bir .jar dosyası içindeyseniz, bir Dosya () oluşturamazsınız ve bu klasör için bir URL de alamazsınız ... Ben şahsen onunla barışa geldim ve her dosyayı bir XML'de listeledim ... Bunu bir kavanoz dosyası içindeki bir klasör için yapabileceğinizi düşünüyorum ...
Mostafa Zeinali

2
Sorunlarınız için üzgünüm. Ancak, kod tabanınız bir jar dosyasında ve kaynaklarınız da bu kavanoz dosyasında olduğunda aslında çalışır. Diskte bir Dosya () oluşturmuyorsunuz - jar dosyasındaki Dosyayı java belleğine okuyorsunuz. ClassLoader'ın diskteki bir dizine eşdeğer bir jar dosyasını işlemekten oldukça mutlu olduğunu unutmayın. Kaynaktan detaylar:
Glen Best

1
Kodu bir kavanozun üzerine koydum ve hatayı aldım ... ayy. V üzgünüm, benim hatam. Jar URL yolunu "Dosya: ...! / Dir1 / dir2 ..." ile işlemeniz gerekir. İki düzeltme: stackoverflow.com/questions/1429172/… VEYA Dize jarPath = dirURL.getPath (). Substring (5, dirURL.getPath (). İndexOf ("!")); JarFile jar = yeni JarFile (URLDecoder.decode (jarPath, "UTF-8")); Numaralandırma <JarEntry> girişleri = jar.entries (); while (entry.hasMoreElements ()) {// bir şey yap}
Glen Best

3
Javadoc'tan, yöntemin DAİMA her durumda bir dosyayı döndürme garantisi olmadığı açıktır. AMA, eğer gerçekten Q'yu okursanız, OP'nin inşaat ile dosya ve klasörlerle çalıştığı% 100 garantilidir. Q, dizinlere ve dosyalara erişmek istiyor - bu, API'nın genel soyutlamasından daha belirgindir. Dosyaya dönüştürme ihtiyacı karşılamak için uygun ve doğrudur. Bu tür çelişkili yorumlar göndermeden önce lütfen Q'yu düzgün bir şekilde okuyun. Şerefe.
Glen Best

7
OP, dosyalar ve dizinlerle çalışmaz. Bir JAR dosyasındaki kaynaklarla çalışıyor. JAR dosyasındaki kaynaklar dosya veya dizin değildir ve Filesınıfla listelenemez . Bu kod bir JAR dosyasındaki kaynaklarla çalışmaz. Dönemi.
Lorne Marquis

7

Bunun yıllar önce olduğunu biliyorum. Ama sadece diğer insanlar için bu konuya rastlıyoruz. Yapabileceğiniz şey getResourceAsStream()yöntemi dizin yolu ile kullanmaktır ve Stream girişi o dizindeki tüm dosya isimlerine sahip olacaktır. Bundan sonra dir yolunu her dosya adıyla birleştirebilir ve bir döngüdeki her dosya için getResourceAsStream öğesini çağırabilirsiniz.


7
Ortaya çıkan şeyleri karıştırmayı planlamıyorsanız bu iyi çalışır.
Tustin2121

1
Temiz olduğundan ve ayrı durumlarda kavanoz ve IDE sürümlerinin kullanılmasını gerektirmediği için bunun kabul edilen bir çözüm olması gerektiğini düşünüyorum. Her ne kadar getResource neden klasörü bulamıyorum ama getResourceAsStream bulur emin değilim.
Raghuram Onti Srinivasan

6

Ben IDE ve kavanoz (sürüm) hem kavanoz ... paketlenmiş kaynaklardan bazı hadoop yapılandırmalar yüklemeye çalışırken ben de aynı sorunu vardı.

java.nio.file.DirectoryStreamHem yerel dosya sistemi hem de jar üzerinden dizin içeriğini yinelemek için en iyi şekilde çalıştım .

String fooFolder = "/foo/folder";
....

ClassLoader classLoader = foofClass.class.getClassLoader();
try {
    uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
    throw new FooException(e.getMessage());
} catch (NullPointerException e){
    throw new FooException(e.getMessage());
}

if(uri == null){
    throw new FooException("something is wrong directory or files missing");
}

/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
    /** jar case */
    try{
        URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
        //jar.toString() begins with file:
        //i want to trim it out...
        Path jarFile = Paths.get(jar.toString().substring("file:".length()));
        FileSystem fs = FileSystems.newFileSystem(jarFile, null);
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
        for(Path p: directoryStream){
            InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
        performFooOverInputStream(is);
        /** your logic here **/
            }
    }catch(IOException e) {
        throw new FooException(e.getMessage());     
    }
}
else{
    /** IDE case */
    Path path = Paths.get(uri);
    try {
        DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
        for(Path p : directoryStream){
            InputStream is = new FileInputStream(p.toFile());
            performFooOverInputStream(is);
        }
    } catch (IOException _e) {
        throw new FooException(_e.getMessage());
    }
}

Bu benim için iyi çalıştı. Yalnızca 'Path jarFile = Paths.get (jar.toString (). Substring ("file:". Length ()));' 'Path jarFile = Paths.get (jar.toURI ());' Windows'da çalışmasını sağlamak için. Ayrıca FileSystem nesnesi için bir kaynak ifadesi ile bir deneme kullanılır.
Jarle Jacobsen

Bu benim için çalıştı! Docker'da dropwizard uygulaması çalıştırıyordum.
nIKUNJ

4

Aşağıdaki kod, bir kavanozun içinde olup olmamasına bakılmaksızın istenen "klasörü" Yol olarak döndürür.

  private Path getFolderPath() throws URISyntaxException, IOException {
    URI uri = getClass().getClassLoader().getResource("folder").toURI();
    if ("jar".equals(uri.getScheme())) {
      FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
      return fileSystem.getPath("path/to/folder/inside/jar");
    } else {
      return Paths.get(uri);
    }
  }

Java 7+ gerekir.


Güzel! Yine de, FileSystem'in Closeable olduğunu eklemeliyim, bu da sistem kaynaklarını serbest bırakmak için bir noktada kapatmanız gerektiği anlamına geliyor. Tabii ki, döndürülen Yol bundan hemen sonra geçersiz hale gelecektir.
Kirill Gamazkov

Bir jar dosyası durumunda , dosya sistemi oluşturulurken kaynağın adının (burada paket + folder) yok sayıldığını unutmayın. Bu nedenle getPathgeri dönmez folder/path/to/..., sadece path/to/....
Marcono1234

1

Başka bir çözüm, bunu kullanarak yapabilirsiniz ResourceLoader:

import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;

@Autowire
private ResourceLoader resourceLoader;

...

Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
    load(fi.next())
}

0

Basit ... OSGi kullanın. OSGi'de, paketinizin findEntries ve findPaths ile girişlerini yineleyebilirsiniz.


10
OSGI içeriyorsa, buna 'basit' diyorum. Ama zaten OSGI kullanıyorsan ... evet eminim. Ancak bu sorunu çözmek için OSGI'ya geçmeyi önermek biraz fazla görünüyor.
Kris

OSGi ayrıca diğer birçok sorunu da çözüyor ve bugünlerde başlamak çok kolay. OSGi enRoute eğiticilerine bakın
Peter Kriens

Zaten kullanmanız gerekmedikçe OSGi'den uzak dururum. 90'lı IMO'nun dağıtım sorunlarını çözen aşırı tasarlanmış Bloatware.
user2337270

-1

Kavanoz dosyamın içinde Yükle adlı bir klasör vardı, bu klasörün içinde üç başka metin dosyası vardı ve kavanoz dosyasının dışında tam olarak aynı klasör ve dosyalara ihtiyacım vardı, aşağıdaki kodu kullandım:

URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);

URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);

URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);

1
Merhaba, cevap için teşekkürler, ama, gördüğünüz gibi, kodu yazarken bu klasörün içindeki her dosyanın adını bilmeniz gerekiyordu; ve her birini açıkça adlandırmanız gerekiyordu. Ne aradığım klasör içindeki dosyaları yineleme ve isimlerini çalışma zamanında almak için bir yöntemdi, bu yüzden kodu değiştirmeden, kodu da işleyeceğini bilerek klasöre kaynak ekleyebilirim. Zaman ayırdığınız için teşekkürler. : 3
Mostafa Zeinali

-1

Diğer cevapların da işaret ettiği gibi, kaynaklar bir jar dosyasının içine girdikten sonra işler gerçekten çirkinleşir. Bizim durumumuzda, bu çözüm:

https://stackoverflow.com/a/13227570/516188

testlerde çok iyi çalışır (testler çalıştırıldığında kod bir jar dosyasında paketlenmediğinden), ancak uygulama gerçekten normal çalıştığında çalışmaz. Yaptığım şey ... Uygulamadaki dosyaların listesini sabit kodluyorum, ancak gerçek listeyi diskten okuyan bir test var (testlerde çalıştığından beri yapabilir) ve gerçek liste yoksa uygulamanın döndürdüğü listeyle eşleşmiyor.

Bu şekilde uygulamamda basit bir kod var (hile yok) ve eminim test sayesinde listeye yeni bir giriş eklemeyi unutmadım.


-25

Bu bağlantı size nasıl yapılacağını anlatır.

Sihirli getResourceAsStream () yöntemidir:

InputStream is = 
this.getClass().getClassLoader().getResourceAsStream("yourpackage/mypackage/myfile.xml")

20
Hayır dostum!! Tek bir dosya istemiyorum !! Ben alt dosyaları önceden çalışma zamanı olan bir klasör istiyorum !!!
Mostafa Zeinali
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.