Bir dosyayı InputStream olarak yüklemenin farklı yolları


216

Arasındaki fark nedir:

InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName)

ve

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)

ve

InputStream is = this.getClass().getResourceAsStream(fileName)

Her biri ne zaman diğerlerinden daha uygun?

Okumak istediğim dosya sınıf yolunda dosyayı okuyan sınıfım. Sınıfım ve dosya aynı kavanozda ve bir EAR dosyasında paketlenmiş ve WebSphere 6.1'de dağıtılmıştır.

Yanıtlar:


289

fileNameGeçtiğiniz şeyin nasıl yorumlandığı konusunda küçük farklılıklar vardır . Temel olarak, 2 farklı yönteminiz vardır: ClassLoader.getResourceAsStream()ve Class.getResourceAsStream(). Bu iki yöntem kaynağı farklı şekilde bulur.

İçinde Class.getResourceAsStream(path), yol, çağırdığınız sınıfın paketinin yerel yolu olarak yorumlanır. Örnek arama için, String.getResourceAsStream("myfile.txt")aşağıdaki konumda adresinden sınıf yolunda bir dosya arar: "java/lang/myfile.txt". Yolunuz a ile başlıyorsa /, mutlak bir yol olarak kabul edilir ve sınıf yolunun kökünden aramaya başlar. Yani arama String.getResourceAsStream("/myfile.txt"), sınıf yolunuzda aşağıdaki konuma bakacaktır ./myfile.txt.

ClassLoader.getResourceAsStream(path)tüm yolları mutlak yollar olarak kabul eder. Yani çağıran String.getClassLoader().getResourceAsStream("myfile.txt")ve String.getClassLoader().getResourceAsStream("/myfile.txt")irade aşağıdaki konumda adresinden sınıf yolunda bir dosya için hem görünüm: ./myfile.txt.

Bu yazıda bir konumdan her bahsettiğimde, kaynağı yüklediğiniz Sınıf ve / veya ClassLoader'a bağlı olarak dosya sisteminizin kendisinde veya karşılık gelen jar dosyasının içinde bir konum olabilir.

Sizin durumunuzda, sınıfı bir Uygulama Sunucusundan yüklüyorsunuz, Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)bunun yerine bunu kullanmalısınız this.getClass().getClassLoader().getResourceAsStream(fileName). this.getClass().getResourceAsStream()de işe yarayacak.

Söz konusu sorun hakkında daha ayrıntılı bilgi için bu makaleyi okuyun .


Tomcat 7 ve önceki sürüm kullanıcıları için uyarı

Bu sorunun cevaplarından biri Tomcat 7 için açıklamamın yanlış göründüğünü söylüyor. Bunun neden böyle olduğunu görmek için etrafa bakmaya çalıştım.

Tomcat'in WebAppClassLoaderçeşitli versiyonları için Tomcat'in kaynak koduna baktım . Uygulanması findResource(String name)(istenen kaynağa URL'yi üretmek için utimately sorumludur) Tomcat 6 ve Tomcat 7 neredeyse aynıdır, ancak Tomcat 8 farklıdır.

Sürüm 6 ve 7'de, uygulama kaynak adını normalleştirmeye çalışmaz. Bu, bu sürümlerde, olayla classLoader.getResourceAsStream("/resource.txt")aynı sonucu vermeyebileceği anlamına gelir classLoader.getResourceAsStream("resource.txt")(Javadoc'un belirttiği gibi). [kaynak kodu]

Bununla birlikte, sürüm 8'de, kaynak adının mutlak sürümünün kullanılan ad olduğunu garanti etmek için kaynak adı normalleştirilir. Bu nedenle, Tomcat 8'de yukarıda açıklanan iki çağrı daima aynı sonucu döndürmelidir. [kaynak kodu]

Sonuç olarak, 8 yaşından küçük Tomcat sürümlerini kullanırken ClassLoader.getResourceAsStream()veya kullanırken çok dikkatli Class.getResourceAsStream()olmanız gerekir. Ayrıca, class.getResourceAsStream("/resource.txt")gerçekten arama yaptığını da unutmayın classLoader.getResourceAsStream("resource.txt")(öncü /soyulmuş).


2
Bundan getClass().getResourceAsStream("/myfile.txt")farklı davrandığından eminim getClassLoader().getResourceAsStream("/myfile.txt").
Brian Gordon

@BrianGordon: Farklı davranmıyorlar. Aslında, Class.getResourceAsStream (String) için javadoc şu şeyi söylüyor: "Bu yöntem, bu nesnenin sınıf yükleyicisine delege ediyor." classloader.
LordOfThePigs

@LordOfThePigs Gerçek kaynağa bakın. Mutlak bir yol sağlarsanız, Class.getResourceAsStream önde gelen eğik çizgiyi kaldırır.
Brian Gordon

4
@BrianGordon: Bu, ClassLoader.getResourceAsStream () ile tam olarak aynı şekilde davranmasını sağlar; çünkü ikincisi, önde gelen eğik çizgi ile başlasalar da başlamasalar da tüm yolları mutlak olarak yorumlar. Yolunuz mutlak olduğu sürece, her iki yöntem de aynı şekilde davranır. Yolunuz göreceli ise, davranış farklıdır.
LordOfThePigs

Bulamadım getClassLoader(), Stringbir hata mı yoksa bir uzantıya mı ihtiyacınız var?
AaA

21

Kodunuzla MyClass.class.getClassLoader().getResourceAsStream(path)ilişkili kaynağı yüklemek için kullanın . MyClass.class.getResourceAsStream(path)Kısayol olarak ve sınıfınızın paketinde paketlenmiş kaynaklar için kullanın .

Thread.currentThread().getContextClassLoader().getResourceAsStream(path)İstemci kodunun parçası olan ve arama koduyla sıkı sıkıya bağlı olmayan kaynakları almak için kullanın . İş parçacığı bağlam sınıfı yükleyicisi herhangi bir şeye işaret ediyor olabileceğinden buna dikkat etmelisiniz.


6

Düz eski Java 7 üzerinde düz eski Java ve başka hiçbir bağımlılık farkı göstermez ...

Ben koymak file.txtiçinde c:\temp\ve ben koymak c:\temp\üzerinde sınıf.

İki çağrı arasında bir fark olduğu tek bir durum vardır.

class J {

 public static void main(String[] a) {
    // as "absolute"

    // ok   
    System.err.println(J.class.getResourceAsStream("/file.txt") != null); 

    // pop            
    System.err.println(J.class.getClassLoader().getResourceAsStream("/file.txt") != null); 

    // as relative

    // ok
    System.err.println(J.class.getResourceAsStream("./file.txt") != null); 

    // ok
    System.err.println(J.class.getClassLoader().getResourceAsStream("./file.txt") != null); 

    // no path

    // ok
    System.err.println(J.class.getResourceAsStream("file.txt") != null); 

   // ok
   System.err.println(J.class.getClassLoader().getResourceAsStream("file.txt") != null); 
  }
}

çok teşekkürler, benim için sadece 'J.class.getResourceAsStream ("file.txt")' çalıştı
abbasalim

3

Buralarda Bütün bu cevaplar yanı sıra cevaplar bu soruya , "/foo/bar.properties" aynı muamele gibi bu yükleme mutlak URL'ler, önermek class.getResourceAsStream(String)ve class.getClassLoader().getResourceAsStream(String). En azından Tomcat yapılandırmamda / versiyonunda (şu anda 7.0.40) durum böyle değil.

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

Üzgünüm, kesinlikle tatmin edici bir açıklamam yok, ama sanırım tomcat kirli yükler ve kara büyüsünü sınıf yükleyicilerle yapıyor ve fark yaratıyor. Her zaman class.getResourceAsStream(String)geçmişte kullandım ve hiç problem yaşamadım.

Not: Bunu da buraya gönderdim


Belki tomcat şartnameye uymamaya karar verir ve geçirilen tüm yolları ClassLoader.getResourceAsStream()mutlak kabul etmez ? Bu, bazı yorumlarda belirtildiği gibi, Class.getResourceAsStreamaslında getClassLoader (). GetResourceAsStream` öğesini çağırır , ancak herhangi bir önde gelen eğik çizgiyi çıkarır.
LordOfThePigs

Java SE kaynak kodunu kontrol ettikten sonra, yanıtı tutun düşünüyorum: Her ikisi de Class.getResourceAsStream()ve ClassLoader.getResourceAsStream()nihayetinde ClassLoader.findResource()varsayılan uygulaması boş olan, ancak javadoc açıkça "Sınıf yükleyici uygulamaları nerede belirtmek için bu yöntemi geçersiz kılmalıdır kaynakları bulmak için ". Tomcat'in bu özel yöntemi uygulamasının hatalı olabileceğinden şüpheleniyorum.
LordOfThePigs

Ben de uygulanmasını karşılaştırıldığında ettik WebAppClassLoader.findResource(String name)içinde Tomcat 7 o ile Tomcat 8 ve bir temel fark vardır anlaşılmaktadır. Tomcat 8 /, içermeyen bir satır aralığı ekleyerek kaynak adını açıkça normalleştirir , bu da tüm adları mutlak yapar. Tomcat 7 bilmiyor. Tomcat 7
LordOfThePigs

Cevabımda buna bir paragraf ekledim.
LordOfThePigs

0

Dosyayı başarılı bir şekilde yüklemenin bazı yollarını denedikten sonra FileInputStream, mükemmel bir şekilde çalışabileceğimi hatırladım .

InputStream is = new FileInputStream("file.txt");

Bu dosyayı bir dosyaya okumanın başka bir yoludur InputStream, dosyayı o anda çalışan klasörden okur.


Bu bir dosya değil, bir kaynak. Cevap doğru değil.
Lorne Marquis

1
@EJP Bir dosya ve kaynak arasındaki farkı bilmeden bir dosya yükleme yollarını arayarak bu SO cevabına giriyorum. Cevabımı silmeyeceğim çünkü başkalarına yardımcı olabilir.
António Almeida

-3

Çalışır, şunu deneyin:

InputStream in_s1 =   TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");
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.