Ada perbedaan halus tentang bagaimana fileName
Anda menyampaikan ditafsirkan. Pada dasarnya, Anda memiliki 2 metode berbeda: ClassLoader.getResourceAsStream()
dan Class.getResourceAsStream()
. Kedua metode ini akan menemukan sumber daya secara berbeda.
Di Class.getResourceAsStream(path)
, path ditafsirkan sebagai path lokal ke paket dari kelas yang Anda panggil. Misalnya panggilan, String.getResourceAsStream("myfile.txt")
akan mencari file di classpath Anda di lokasi berikut: "java/lang/myfile.txt"
. Jika path Anda dimulai dengan a /
, maka itu akan dianggap sebagai path absolut, dan akan mulai mencari dari akar classpath. Jadi panggilan String.getResourceAsStream("/myfile.txt")
akan melihat lokasi berikut di jalur kelas Anda ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
akan menganggap semua jalur sebagai jalur absolut. Jadi menelepon String.getClassLoader().getResourceAsStream("myfile.txt")
dan String.getClassLoader().getResourceAsStream("/myfile.txt")
akan baik mencari file di classpath Anda di lokasi berikut: ./myfile.txt
.
Setiap kali saya menyebutkan lokasi dalam posting ini, itu bisa menjadi lokasi di sistem file Anda sendiri, atau di dalam file jar yang sesuai, tergantung pada Kelas dan / atau ClassLoader tempat Anda memuat sumber daya.
Dalam kasus Anda, Anda memuat kelas dari Application Server, sehingga Anda harus menggunakan Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
bukan this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
juga akan bekerja.
Baca artikel ini untuk informasi lebih rinci tentang masalah khusus itu.
Peringatan untuk pengguna Tomcat 7 dan di bawah
Salah satu jawaban untuk pertanyaan ini menyatakan bahwa penjelasan saya tampaknya tidak benar untuk Tomcat 7. Saya sudah mencoba melihat-lihat untuk melihat mengapa itu akan terjadi.
Jadi saya telah melihat kode sumber Tomcat WebAppClassLoader
untuk beberapa versi Tomcat. Implementasi findResource(String name)
(yang sepenuhnya bertanggung jawab untuk menghasilkan URL ke sumber daya yang diminta) sebenarnya identik dalam Tomcat 6 dan Tomcat 7, tetapi berbeda dalam Tomcat 8.
Dalam versi 6 dan 7, implementasi tidak berusaha untuk menormalkan nama sumber. Ini berarti bahwa dalam versi-versi ini, classLoader.getResourceAsStream("/resource.txt")
mungkin tidak menghasilkan hasil yang sama seperti classLoader.getResourceAsStream("resource.txt")
peristiwa meskipun seharusnya (karena apa yang ditentukan oleh Javadoc). [Kode sumber]
Namun dalam versi 8, nama sumber dinormalisasi untuk menjamin bahwa versi absolut dari nama sumber adalah yang digunakan. Oleh karena itu, dalam Tomcat 8, dua panggilan yang dijelaskan di atas harus selalu mengembalikan hasil yang sama. [Kode sumber]
Akibatnya, Anda harus ekstra hati-hati saat menggunakan ClassLoader.getResourceAsStream()
atau Class.getResourceAsStream()
pada versi Tomcat lebih awal dari 8. Dan Anda juga harus ingat bahwa class.getResourceAsStream("/resource.txt")
panggilan sebenarnya classLoader.getResourceAsStream("resource.txt")
(pemimpin /
dilucuti).
getClass().getResourceAsStream("/myfile.txt")
berperilaku berbeda darigetClassLoader().getResourceAsStream("/myfile.txt")
.getClassLoader()
dariString
, apakah itu kesalahan atau butuh perpanjangan?Gunakan
MyClass.class.getClassLoader().getResourceAsStream(path)
untuk memuat sumber daya yang terkait dengan kode Anda. GunakanMyClass.class.getResourceAsStream(path)
sebagai jalan pintas, dan untuk sumber daya yang dikemas dalam paket kelas Anda.Gunakan
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
untuk mendapatkan sumber daya yang merupakan bagian dari kode klien, tidak terikat dengan ketat pada kode panggilan. Anda harus berhati-hati dengan ini karena loader kelas konteks thread dapat menunjuk pada apa saja.sumber
Java tua polos di Java 7 polos dan tidak ada dependensi lain yang menunjukkan perbedaan ...
Saya dimasukkan ke
file.txt
dalamc:\temp\
dan saya memakaic:\temp\
classpath.Hanya ada satu kasus di mana ada perbedaan antara keduanya.
sumber
Semua jawaban di sekitar sini, serta jawaban dalam pertanyaan ini , menyarankan bahwa memuat URL absolut, seperti "/foo/bar.properties" diperlakukan sama oleh
class.getResourceAsStream(String)
danclass.getClassLoader().getResourceAsStream(String)
. Ini BUKAN kasusnya, setidaknya tidak dalam konfigurasi / versi Tomcat saya (saat ini 7.0.40).Maaf, saya sama sekali tidak memiliki penjelasan yang memuaskan, tapi saya kira kucing jantan melakukan trik kotor dan sihir hitamnya dengan classloader dan menyebabkan perbedaan. Saya selalu menggunakan
class.getResourceAsStream(String)
di masa lalu dan tidak punya masalah.PS: Saya juga memposting ini di sini
sumber
ClassLoader.getResourceAsStream()
sebagai mutlak? Ini masuk akal karena seperti yang disebutkan dalam beberapa komentar di atas,Class.getResourceAsStream
sebenarnya memanggil getClassLoader (). GetResourceAsStream` tetapi menghapus semua garis miring utama.Class.getResourceAsStream()
danClassLoader.getResourceAsStream()
akhirnya memanggilClassLoader.findResource()
yang merupakan metode yang dilindungi yang implementasi standarnya kosong, tetapi yang javadoc secara eksplisit menyatakan "Implementasi loader kelas harus mengganti metode ini untuk menentukan di mana untuk menemukan sumber daya ". Saya menduga implementasi tomcat dari metode khusus ini mungkin cacat.WebAppClassLoader.findResource(String name)
di Tomcat 7 dengan Tomcat 8 , dan tampaknya ada perbedaan utama. Tomcat 8 secara eksplisit menormalkan nama sumber daya dengan menambahkan sebuah arahan/
jika tidak mengandung apa pun, yang membuat semua nama mutlak. Tomcat 7 tidak. Itu jelas bug di Tomcat 7Setelah mencoba beberapa cara untuk memuat file tanpa hasil, saya ingat saya dapat menggunakannya
FileInputStream
, yang bekerja dengan sempurna.Ini adalah cara lain untuk membaca file menjadi
InputStream
, membaca file dari folder yang sedang berjalan.sumber
Berhasil, coba ini:
sumber