getResourceAsStream () ve FileInputStream karşılaştırması


173

Bir web uygulamasında bir dosya yüklemeye çalışıyordum ve FileNotFoundkullandığımda bir istisna alıyordum FileInputStream. Ancak, aynı yolu kullanarak, yaptığım zaman dosyayı yükleyebildim getResourceAsStream(). İki yöntem arasındaki fark nedir ve neden biri diğeri çalışmıyor?

Yanıtlar:


256

java.io.FileVe eşleri yerel disk dosya sistemine etki eder. Sorununuzun temel nedeni, göreli yolların java.iogeçerli çalışma dizinine bağlı olmasıdır. Yani JVM'nin (sizin durumunuzda: web sunucusunun biri) başlatıldığı dizin. Bu, örneğin olabilir C:\Tomcat\binveya tamamen farklı, ama böylece bir şey değil C:\Tomcat\webapps\contextname ya da ne olmasını beklersiniz. Normal bir Eclipse projesinde bu olurdu C:\Eclipse\workspace\projectname. Geçerli çalışma dizini hakkında şu şekilde bilgi edinebilirsiniz:

System.out.println(new File(".").getAbsolutePath());

Ancak, çalışma dizini hiçbir şekilde program aracılığıyla denetlenemez. Gerçekten göreli yollar yerine API'da mutlak yollar kullanmayı tercih etmelisiniz File. ÖrneğinC:\full\path\to\file.ext .

Java (web) uygulamalarında sabit kod yazmak veya mutlak yolu tahmin etmek istemezsiniz. Bu sadece taşınabilirlik sorunudur (yani X sisteminde çalışır, ancak Y sisteminde çalışmaz). Normal uygulama, bu tür kaynakları sınıfyoluna yerleştirmek veya sınıf yoluna tam yolunu eklemektir ( srcsırasıyla klasör ve "oluşturma yolu" olan Eclipse gibi bir IDE'ye ). Eğer yardımıyla onları yakala Bu şekilde ClassLoadertarafından ClassLoader#getResource()veya ClassLoader#getResourceAsStream(). Tesadüfen tesadüf olarak dosyaları sınıf yolunun "kökü" ne göre bulabilir. Web uygulamalarında (veya birden fazla sınıf yükleyici kullanan başka bir uygulamada) ClassLoadertarafından döndürülen şekilde kullanılması önerilir.Thread.currentThread().getContextClassLoader() için böylece webapp bağlamının "dışına" da bakabilirsiniz.

Webapps'teki diğer bir alternatif ServletContext#getResource()ve onun karşılığıdır ServletContext#getResourceAsStream(). webKlasör de dahil olmak üzere webapp projesinin ortak klasöründe bulunan dosyalara erişebilir /WEB-INF. ServletContextMiras yoluyla servlet mevcutturgetServletContext() yöntemle, bunun gibi kullanıldı çağırabilir.

Ayrıca bakınız:



27

getResourceAsStream web uygulamaları için bunu yapmanın doğru yoludur (daha önce öğrendiğiniz gibi).

Bunun nedeni, web uygulamanızı bir WAR'da paketlerseniz dosya sisteminden okuma yapamamanızdır. Bu, bir web uygulamasını paketlemenin doğru yoludur. Bu şekilde taşınabilir, çünkü mutlak bir dosya yoluna veya uygulama sunucunuzun yüklü olduğu yere bağlı değilsiniz.


3
+1 - "çalışamaz" çok güçlü olsa da. (Dosya sisteminden okumak işe yarayabilir, ancak portatif olarak yapmak zor ... ve özellikle kaynak bir JAR'da ise çok daha fazla koddur.)
Stephen C

1
duffy, çok güzel bir cevap ve benim hatamın ne olduğunu açıkladınız, ancak BalusC çok fazla ayrıntıya girdi - bence cevabı iç detayları da bilmek isteyenler için yararlı olacaktır. Umarım kabul edilen cevabı değiştirmeme aldırmazsın!
Vivin Paliath

@Stephen - "Çalışamaz" ın çok güçlü olduğunu düşünmüyorum. Uygulama sunucusuna giden farklı yollara sahip iki farklı sunucuya dağıtılması kadar basit bir şey bile onu kıracaktır. Mesele şu ki, WAR'nizi olabildiğince bağımsız bir hale getirmeniz gerekiyor. Demek istediğin doğru, ama ifadelerime bağlı kalacağım.
duffymo

14

FileInputStream , Java işleminin çalışma dizinine göre kurucuya ilettiğiniz dosya yolunu yükler . Genellikle bir web kapsayıcısında, bu binklasör gibi bir şeydir .

getResourceAsStream()uygulamanızın sınıfyolundan göreceli olarak bir dosya yolu yükler .


12

FileInputStreamSınıf altta yatan dosya sistemi ile doğrudan çalışır. Söz konusu dosya orada fiziksel olarak mevcut değilse, dosyayı açamaz. getResourceAsStream()Yöntem farklı çalışır. Çağrıldığı ClassLoadersınıfın kaynağını kullanarak kaynağı bulmaya ve yüklemeye çalışır . Bu, örneğin jardosyalara katıştırılmış kaynakları bulmasını sağlar .


Bir kavanozun içindeki dosyalar fiziksel olarak bir dosya sisteminde hala "mevcut" dur, sadece diğer dosyalarda yer alıyor
matt b

1
Evet, elbette. Ancak, uygulama jardosya formatı ve sonuçları hakkında bilgi sahibi olmadıkça, genellikle dosya sisteminde bağımsız varlıklar olarak görülen bir şey değildir . Ve Java'da uygun ClassLoaderbilgi bu bilgiye sahip olabilir, oysa bir ova FileInputStreamkesinlikle yoktur.
Dirk

7

classname.getResourceAsStream (), classname sınıf yükleyicisi aracılığıyla bir dosya yükler. Sınıf bir jar dosyasından geldiyse, kaynak buradan yüklenir.

FileInputStream, dosya sisteminden bir dosyayı okumak için kullanılır.


0

Ben burada Dosya Okuma (java.io) ve Kaynak Okuma (ClassLoader.getResourceAsStream ()) olarak işaretleyerek hem kullanımları ayırarak buradayım.

Dosya Okuma - 1. Yerel dosya sisteminde çalışır. 2. Geçerli JVM tarafından başlatılan dizinden istenen dosyayı kök olarak bulmaya çalışır 3. / dev / files veya C: \ Data gibi önceden belirlenmiş bir konumda dosyaları işlemek için idealdir.

Kaynak Okuma - 1. Sınıf yolu üzerinde çalışır 2. Geçerli veya üst sınıf yükleyici sınıfyolunda dosyayı / kaynağı bulmaya çalışır. 3. Savaş veya kavanoz gibi paketlenmiş dosyalardan dosya yüklemeye çalışırken idealdir.

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.