getResourceAsStream null değerini döndürür


183

Java projemin derlenmiş bir JAR'ında bir paketin içinden bir metin dosyası yüklüyorum. İlgili dizin yapısı aşağıdaki gibidir:

/src/initialization/Lifepaths.txt

Kodum Class::getResourceAsStreamgeri dönmek için çağırarak bir dosya yükler InputStream.

public class Lifepaths {
    public static void execute() {
        System.out.println(Lifepaths.class.getClass().
            getResourceAsStream("/initialization/Lifepaths.txt"));
    }

    private Lifepaths() {}

    //This is temporary; will eventually be called from outside
    public static void main(String[] args) {execute();}
}

nullNe kullandığım önemli değil, çıktılar her zaman yazdırılır . Yukarıdakilerin neden işe yaramadığından emin değilim, bu yüzden de denedim:

  • "/src/initialization/Lifepaths.txt"
  • "initialization/Lifepaths.txt"
  • "Lifepaths.txt"

Bunların hiçbiri işe yaramıyor. Ben ettik okumak sayısız sorular bugüne kadar konuyla ilgili, ancak bunların hiçbiri yararlı olmuştur - genellikle, sadece zaten yapıyorum Kök yolunu kullanarak yük dosyalarına derler. Bu, ya da sadece filenamedenedim geçerli dizinden (sadece yük ) dosyayı yükleyin . Dosya, JAR'da uygun adda ve uygun adla derleniyor.

Bunu nasıl çözerim?


3
Eğer gerçekten o kadar kontrol ettiniz olduğu Kavanoz dosyasında? Dosya kasasını kontrol ettiniz mi?
Jon Skeet

@JonSkeet Gerçekten uygun konumdaki JAR dosyasına derlenmektedir ve durum doğrudur.

1
@greedybuddha Bunu statik bir bağlamdan çağıramıyor olsam da, onu kullanarak çağırabilirim Lifepaths.class. Olduğu söyleniyor, neden getClassLoader()çalışmasına izin veriyor? (Ayrıca, bir cevap göndermek için çekinmeyin!)

Gösterebilir misin Lifepaths.getClass()?
Object'de

1
Bu cevaba bir göz atın ve kullanarak çalıştırabileceğinizi görün getResource(String). BTW - Bunlardan herhangi birinin bir staticbağlamda çalışmasını sağlamakta her zaman sorun yaşadım . Sorun temel olarak elde edilen sınıf yükleyicinin J2SE sınıflarına yönelik olmasıdır. Uygulamanın kendisi için tasarlanan bağlam sınıfı yükleyiciye erişmeniz gerekir .
Andrew Thompson

Yanıtlar:


159

Lifepaths.class.getClass().getResourceAsStream(...) kaynakları sistem sınıfı yükleyiciyi kullanarak yükler, JAR'larınızı görmediği için başarısız olur

Lifepaths.class.getResourceAsStream(...) Lifepaths sınıfını yükleyen aynı sınıf yükleyiciyi kullanarak kaynakları yükler ve JAR'larınızdaki kaynaklara erişimi olmalıdır


129
Sadece eklemek için, getResourceAsStream (name) çağrılırken, ad "/" ile başlamalıdır. Bunun gerekli olup olmadığından emin değilim, ama onsuz problemim var.
David

3
Ben bu / dün sabah 8 am beri vidalı. Beni kurtardı. Ayrıca çalışması için önde gelen bir eğik çizgiye ihtiyacım vardı.
kyle

4
Ayrıca, istenen kaynağın paketler hiyerarşisinin dışında olabileceğini unutmayın. Bu durumda, kaynağınıza ulaşmak için yolunuzda "../" kullanmanız ve ardından bir düzey yukarı, ardından başka bir yol dalına gitmeniz gerekir.
Zon

3
@David - Sanırım ('/' önde gelen) gerekli aksi takdirde Lifepaths.class paketine göre arama yapar
Mz A

5
Sadece bazı bilgiler eklemek için /, dosyanız farklı bir dizinin altındaysa yolunuzdan önce a eklemeniz gerekir ; örneğin initialization/Lifepaths.txt. Dosyanın yolu yout sınıfıyla aynıysa (ancak ana dizin olarak kaynaklar altında) dosyanın adını herhangi bir olmadan koyabilirsiniz /. Örneğin, sınıfınızda aşağıdaki yol varsa src/main/java/paths/Lifepaths.java, dosyanız bu yola sahip olmalıdır src/main/resources/paths/Lifepaths.txt.
Dwhitz

60

Kurallar aşağıdaki gibidir:

  1. JAR'ın içine yüklemek istediğiniz dosyanın konumunu kontrol edin (ve bu dosyanın JAR'a gerçekten eklendiğinden emin olun)
  2. mutlak bir yol kullanın: yol JAR'ın kökünden başlar
  3. göreli bir yol kullan: yol, çağırdığınız sınıfın paket dizininde başlar getResource / getResoucreAsStream

Ve dene:

Lifepaths.class.getResourceAsStream("/initialization/Lifepaths.txt")

onun yerine

Lifepaths.class.getClass().getResourceAsStream("/initialization/Lifepaths.txt")

(bir fark yaratıp yaratmadığından emin değilim, ancak birincisi doğru ClassLoader / JAR'ı kullanacak, ikincisinden emin değilim)


2
Bunların üçünü de zaten yaptım. Lütfen sorumu tekrar okuyun.

Sorunuzdan "İlgili dizin yapısı" nın ne olduğu ve dosyanın JAR'da olup olmadığını ve nerede olduğunu gerçekten kontrol ettiyseniz (adım 1)
16'da Puce

1
Göreceli yol hakkındaki görüşünüz sonunda sorunu çözdü; Teşekkürler!
Paul Bormans

İlginç. Ona ulaşmak için "/config.properties" (eğik çizgi ile) yapmak zorunda kaldım ...
Erk

45

Bu nedenle, bir kavanozdan kaynak almanın birkaç yolu vardır ve her birinin yolun farklı şekilde belirtilmesi gereken biraz farklı sözdizimi vardır.

Gördüğüm en iyi açıklama JavaWorld'ün bu makalesi . Burada özetleyeceğim, ancak daha fazla bilgi edinmek istiyorsanız makaleye göz atmalısınız.

Yöntemler

1) ClassLoader.getResourceAsStream().

Biçim: "/" - ayrılmış isimler; baştaki "/" yok (tüm isimler mutlak).

Misal: this.getClass().getClassLoader().getResourceAsStream("some/pkg/resource.properties");

2) Class.getResourceAsStream()

Biçim: "/" - ayrılmış isimler; baştaki "/" mutlak adları belirtir; diğer tüm isimler sınıfın paketine göredir

Misal: this.getClass().getResourceAsStream("/some/pkg/resource.properties");


ikinci örneğiniz bozuldu
Janus Troelsen

1
İkinci örnek kırık değil, cevabımda söylediğim gibi, kaynağın bulunduğu yere bağlıdır.
greedybuddha

Ayrıca: Kaynak klasörü yenileyerek IDE'nizin dosyayı ('some / pkg / resource.properties') gördüğünden emin olun.
Eric Duminil

15

Mutlak yollar kullanmayın, bunları projenizdeki 'kaynaklar' dizinine göreli hale getirin. 'Kaynaklar' dizininden MyTest.txt içeriğini görüntüleyen hızlı ve kirli kod.

@Test
public void testDefaultResource() {
    // can we see default resources
    BufferedInputStream result = (BufferedInputStream) 
         Config.class.getClassLoader().getResourceAsStream("MyTest.txt");
    byte [] b = new byte[256];
    int val = 0;
    String txt = null;
    do {
        try {
            val = result.read(b);
            if (val > 0) {
                txt += new String(b, 0, val);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
    } while (val > -1);
    System.out.println(txt);
}


8

Kullandığınız ClassLoader ile ilgili bir sorun var gibi görünüyor. Sınıf yüklemek için contextClassLoader kullanın. Bu, statik / statik olmayan bir yöntemde olup olmadığına bakılmaksızın

Thread.currentThread().getContextClassLoader().getResourceAsStream......


6

Kendimi de benzer bir konuda buldum. Maven kullandığım için pom.xml'i böyle bir şey içerecek şekilde güncellemem gerekiyordu:

   ...
</dependencies>
<build>
    <resources>
        <resource>
            <directory>/src/main/resources</directory>
        </resource>
        <resource>
            <directory>../src/main/resources</directory>
        </resource>
    </resources>
    <pluginManagement>
        ...

Bu klasörün nerede olduğunu belirtmek için oradaki kaynak etiketine dikkat edin. İç içe geçmiş projeleriniz varsa (benim yaptığım gibi), yalnızca çalıştığınız modül yerine başka alanlardan kaynak almak isteyebilirsiniz. Benzer yapılandırma verileri kullanıyorsanız, aynı dosyayı her depoda tutmanıza yardımcı olur


3

Benim için işe yarayan dosyayı altına eklemek My Project/Java Resources/srcve kullanmak

this.getClass().getClassLoader().getResourceAsStream("myfile.txt");

Açıkça bu dosyayı yoluna eklemek zorunda değildi (ekleyerek /srcgörünüşe göre yapar)


Yanlış java sözdizimi
Ilya Kharlamov

2

Yardımın olup olmadığını bilmiyorum, ama benim durumumda / src / klasöründe kaynağım vardı ve bu hatayı alıyordum. Daha sonra resmi bin klasörüne taşıdım ve sorunu düzelttim.


2

Kaynak dizininizin (örn. "Src") sınıf yolunuzda olduğundan emin olun (eclipse içindeki oluşturma yolunuzda bir kaynak dizin olduğundan emin olun).

Clazz'ın ana sınıf yükleyiciden yüklendiğinden emin olun.

Ardından, src / initialization / Lifepaths.txt dosyasını yüklemek için şunu kullanın:

clazz.getResourceAsStream("/initialization/Lifepaths.txt");

Neden: clazz.getResourcesAsStream(foo)foo yukarıya bakar clazz ait sınıf yolu içinde , dizin clazz yaşamlarına göre . Baştaki "/", clazz sınıf yolundaki herhangi bir dizinin kökünden yüklenmesini sağlar.

Tomcat gibi bir kapta değilseniz veya doğrudan ClassLoaders ile bir şey yapmadıkça, eclipse / komut satırı sınıf yolunuzu tek sınıf yükleyici sınıf yolu olarak değerlendirebilirsiniz.


2

Varsayılan JVM classloader ilk kaynak yüklemek için ebeveyn-classloader kullanacağız: deletegate-üst-sınıf yükleyicisi.

Lifepaths.class.getClass()'ın classloader is bootstrap classloaderyüzden getResourceAsStream$ JAVA_HOME bakılmaksızın yalnızca kullanıcının sağlanan arayacaktır classpath. Açıkçası, Lifepaths.txt orada değil.

Lifepaths.class's classloader system classpath classloader, böylece getResourceAsStreamkullanıcı tanımlı arama classpathve Lifepaths.txt orada.

Kullanırken java.lang.Class#getResourceAsStream(String name), '/' ile başlamayan isim package nameönek olarak eklenecektir . Bundan kaçınmak istiyorsanız, lütfen java.lang.ClassLoader#getResourceAsStream. Örneğin:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourceName = "Lifepaths.txt";
InputStream resourceStream = loader.getResourceAsStream(resourceName); 

2

Kabaca konuşma:

getClass().getResource("/") ~ = Thread.currentThread().getContextClassLoader().getResource(".")

Proje yapınızın aşağıdaki gibi olduğunu varsayalım:

├── src
   ├── main
   └── test
   └── test
       ├── java
          └── com
              └── github
                  └── xyz
                      └── proj
                          ├── MainTest.java
                          └── TestBase.java
       └── resources
           └── abcd.txt
└── target
    └── test-classes
        ├── com
        └── abcd.txt
// in MainClass.java
this.getClass.getResource("/") -> "~/proj_dir/target/test-classes/"
this.getClass.getResource(".") -> "~/proj_dir/target/test-classes/com/github/xyz/proj/"
Thread.currentThread().getContextClassLoader().getResources(".") -> "~/proj_dir/target/test-classes/"
Thread.currentThread().getContextClassLoader().getResources("/") ->  null

2

Maven kullanıyorsanız, ambalajınızın 'pom' değil 'jar' olduğundan emin olun.

<packaging>jar</packaging>

0

Gerçekten ihtiyacınız olan şey, dosya için tam bir mutlak classPath. Yani tahmin etmek yerine, KÖK'ü bulmaya çalışın ve ardından dosyayı <.war> dosya yapılarından daha iyi bir konum tabanına taşıyın ...

URL test1 = getClass().getResource("/");
URL test2 = getClass().getClassLoader().getResource("/");            
URL test3 = getClass().getClassLoader().getResource("../");

logger.info(test1.getPath()); 
logger.info(test2.getPath());
logger.info(test3.getPath());

0

Benim için işe yarayan dosyayı altına yerleştirdim

src/main/java/myfile.log

ve

InputStream is = getClass().getClassLoader().getResourceAsStream("myfile.log");
        
        if (is == null) {
            throw new FileNotFoundException("Log file not provided");
        }

Kaynak klasör çağrılır src/main/JAVA, tabii ki kod olmayan dosyalarınız burada bulunmamalıdır.
leyren

-12

@Emracool ... Sana bir alternatif öneririm. Bir * .txt dosyası yüklemeye çalışıyor gibi görünüyor. FileInputStream()Bu can sıkıcı değil getClass().getClassLoader().getResourceAsStream()ya da kullanmak daha iyi getClass().getResourceAsStream(). En azından kodunuz doğru şekilde çalışacaktır.


ne ??? Böyle bir çalışma cevabı için -1. Ne olursa olsun. Ancak yukarıda önerilen çözüm kesin olarak işe yarayacaktır.
Jain
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.