एक इनपुटस्ट्रीम के रूप में फाइल लोड करने के विभिन्न तरीके


216

के बीच क्या अंतर है:

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

तथा

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

तथा

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

हर एक को दूसरों की तुलना में उपयोग करने के लिए अधिक उपयुक्त हैं?

जिस फ़ाइल को मैं पढ़ना चाहता हूं, वह क्लासपाथ में है क्योंकि मेरी क्लास उस फाइल को पढ़ती है। मेरी कक्षा और फ़ाइल एक ही जार में हैं और एक EAR फ़ाइल में पैक की गई है, और इसे वेबस्फेयर 6.1 में तैनात किया गया है।

जवाबों:


289

fileNameआप कैसे गुजर रहे हैं, इसकी व्याख्या करने के लिए सूक्ष्म अंतर हैं। मूल रूप से, आपके पास 2 अलग-अलग विधियाँ हैं: ClassLoader.getResourceAsStream()और Class.getResourceAsStream()। ये दो विधियाँ संसाधन को अलग-अलग तरीके से ढूँढेगी।

में Class.getResourceAsStream(path), पथ को उस पथ के स्थानीय पथ के रूप में व्याख्या किया जाता है जिस वर्ग से आप इसे कॉल कर रहे हैं। उदाहरण के फोन करने के लिए, String.getResourceAsStream("myfile.txt")निम्न स्थान पर अपने classpath में एक फ़ाइल के लिए दिखेगा: "java/lang/myfile.txt"। यदि आपका मार्ग ए से शुरू होता है /, तो इसे एक पूर्ण मार्ग माना जाएगा, और क्लासपाथ की जड़ से खोजना शुरू कर देगा। इसलिए कॉलिंग String.getResourceAsStream("/myfile.txt")आपके क्लास पथ में निम्न स्थान पर दिखेगा ./myfile.txt

ClassLoader.getResourceAsStream(path)सभी रास्तों को निरपेक्ष पथ मानेंगे। इसलिए कॉलिंग String.getClassLoader().getResourceAsStream("myfile.txt")और String.getClassLoader().getResourceAsStream("/myfile.txt")निम्नलिखित स्थान पर दोनों आपके वर्गपथ में एक फ़ाइल की तलाश करेंगे:./myfile.txt

हर बार जब मैं इस पोस्ट में किसी स्थान का उल्लेख करता हूं, तो यह आपके फाइलसिस्टम में ही एक स्थान हो सकता है, या संबंधित जार फ़ाइल के अंदर, आपके द्वारा संसाधन लोड किए जाने वाले वर्ग और / या क्लासऑलडर पर निर्भर करता है।

आपके मामले में, आप अनुप्रयोग सर्वर से कक्षा को लोड कर रहे हैं, इसलिए आपको Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)इसके बजाय का उपयोग करना चाहिए this.getClass().getClassLoader().getResourceAsStream(fileName)this.getClass().getResourceAsStream()काम भी करेगा।

उस विशेष समस्या के बारे में अधिक विस्तृत जानकारी के लिए इस लेख को पढ़ें ।


टॉमकैट 7 और उससे नीचे के उपयोगकर्ताओं के लिए चेतावनी

इस सवाल के जवाब में से एक में कहा गया है कि मेरा स्पष्टीकरण टॉमकैट 7 के लिए गलत लगता है। मैंने यह देखने के लिए चारों ओर देखने की कोशिश की है कि ऐसा क्यों होगा।

इसलिए मैंने टॉमकैट के WebAppClassLoaderकई संस्करणों के लिए टॉमकैट के स्रोत कोड को देखा है । findResource(String name)(जो अनुरोधित संसाधन के लिए URL का उत्पादन करने के लिए अत्यंत उत्तरदायी है) का कार्यान्वयन वस्तुतः Tomcat 6 और Tomcat 7 में समान है, लेकिन Tomcat 8 में भिन्न है।

संस्करण 6 और 7 में, कार्यान्वयन संसाधन नाम को सामान्य करने का प्रयास नहीं करता है। इसका मतलब यह है कि इन संस्करणों में, घटना के classLoader.getResourceAsStream("/resource.txt")रूप में उसी परिणाम का उत्पादन नहीं हो सकता है , classLoader.getResourceAsStream("resource.txt")हालांकि यह होना चाहिए (जब से कि Javadoc निर्दिष्ट करता है)। [सोर्स कोड]

संस्करण 8 में हालांकि, संसाधन नाम की गारंटी सामान्यीकृत है कि संसाधन नाम का पूर्ण संस्करण वह है जिसका उपयोग किया जाता है। इसलिए, टॉमकैट 8 में, ऊपर वर्णित दो कॉल हमेशा एक ही परिणाम वापस करना चाहिए। [सोर्स कोड]

नतीजतन, आपको 8. से पहले ClassLoader.getResourceAsStream()या Class.getResourceAsStream()टॉमकैट संस्करणों का उपयोग करते समय अतिरिक्त सावधानी बरतनी होगी और आपको यह भी ध्यान रखना होगा कि class.getResourceAsStream("/resource.txt")वास्तव में कॉल classLoader.getResourceAsStream("resource.txt")(अग्रणी /छीन लिया गया है)।


2
मुझे पूरा यकीन है कि इससे getClass().getResourceAsStream("/myfile.txt")अलग व्यवहार होता है getClassLoader().getResourceAsStream("/myfile.txt")
ब्रायन गॉर्डन

@BrianGordon: वे अलग व्यवहार नहीं करते। दरअसल, Class.getResourceAsStream (स्ट्रिंग) के लिए javadoc निम्नलिखित बात कहता है: "यह विधि इस ऑब्जेक्ट के क्लास लोडर को दर्शाती है ।" classloader।
लॉर्डऑफइंपल्स

@LordOfThePigs वास्तविक स्रोत को देखें। यदि आप एक निरपेक्ष पथ प्रदान करते हैं तो Class.getResourceAsStream अग्रणी फ़ॉरवर्ड स्लैश को हटा देता है।
ब्रायन गॉर्डन

4
@BrianGordon: जो इसे ClassLoader.getResourceAsStream () के समान व्यवहार करता है क्योंकि बाद वाले सभी पथों को निरपेक्ष बताते हैं, चाहे वे एक प्रमुख स्लैश के साथ शुरू करें या नहीं। इसलिए जब तक आप पथ निरपेक्ष हैं, तब तक दोनों विधियां पहचान का व्यवहार करती हैं। यदि आपका मार्ग सापेक्ष है, तो व्यवहार भिन्न है।
लॉर्डऑफइप्स

मैं नहीं मिल सकता getClassLoader()है String, यह एक गलती है या एक विस्तार की जरूरत है?
AAA

21

MyClass.class.getClassLoader().getResourceAsStream(path)अपने कोड से जुड़े संसाधन लोड करने के लिए उपयोग करें । MyClass.class.getResourceAsStream(path)शॉर्टकट के रूप में उपयोग करें , और आपकी कक्षा के पैकेज में पैक किए गए संसाधनों के लिए।

Thread.currentThread().getContextClassLoader().getResourceAsStream(path)उन संसाधनों को प्राप्त करने के लिए उपयोग करें जो क्लाइंट कोड का हिस्सा हैं, न कि कॉलिंग कोड पर कसकर। आपको इससे सावधान रहना चाहिए क्योंकि थ्रेड संदर्भ वर्ग लोडर किसी भी चीज की ओर इशारा कर सकता है।


6

सादे पुराने जावा 7 पर पुराने जावा और कोई अन्य निर्भरता अंतर को प्रदर्शित नहीं करता है ...

मैं डाल file.txtमें c:\temp\और मैं डालc:\temp\ classpath पर।

केवल एक ही मामला है जहां दो कॉल के बीच अंतर है।

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); 
  }
}

बहुत धन्यवाद, मेरे लिए केवल 'J.class.getResourceAsStream ("file.txt") काम किया
abbasalim

3

यहाँ इन सभी उत्तरों के साथ-साथ इस प्रश्न के उत्तर भी सुझाते हैं कि "/foo/bar.properties" जैसे पूर्ण URL को लोड करके class.getResourceAsStream(String)और उसी के समान व्यवहार किया गया है class.getClassLoader().getResourceAsStream(String)। यह ऐसा नहीं है, कम से कम मेरे टॉमकैट कॉन्फ़िगरेशन / संस्करण (वर्तमान में 7.0.40) में नहीं है।

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

क्षमा करें, मेरे पास पूरी तरह से कोई संतोषजनक स्पष्टीकरण नहीं है, लेकिन मुझे लगता है कि टॉमकैट गंदे चालें करता है और अपने काले जादू को क्लास लोडर के साथ करता है और अंतर का कारण बनता है। मैंने हमेशा इस्तेमाल कियाclass.getResourceAsStream(String) अतीत में और कोई समस्या नहीं है।

पुनश्च: मैंने भी इसे यहाँ पोस्ट किया है


हो सकता है कि टॉमकैट विनिर्देश का सम्मान न करने का फैसला करता है, और ClassLoader.getResourceAsStream()निरपेक्ष के रूप में पारित किए गए सभी रास्तों का इलाज नहीं करता है ? यह प्रशंसनीय है क्योंकि जैसा कि ऊपर कुछ टिप्पणियों में उल्लेख किया गया है, Class.getResourceAsStreamवास्तव में getClassLoader () कहते हैं। getResourceAsStream` लेकिन किसी भी अग्रणी स्लैश को स्ट्रिप्स।
लॉर्डऑफइग्स

जावा एसई के स्रोत कोड में जांच करने के बाद, मुझे लगता है कि मैं उत्तर पकड़ता हूं: दोनों Class.getResourceAsStream()और ClassLoader.getResourceAsStream()अंत में कॉलिंग है ClassLoader.findResource()जो एक संरक्षित तरीका है जिसका डिफ़ॉल्ट कार्यान्वयन खाली है, लेकिन जिसका javadoc स्पष्ट रूप से बताता है "कक्षा लोडर कार्यान्वयन को निर्दिष्ट करने के लिए इस पद्धति को ओवरराइड करना चाहिए जहां संसाधनों को खोजने के लिए ”। मुझे संदेह है कि इस विशेष पद्धति के टोमैट के कार्यान्वयन में त्रुटिपूर्ण हो सकता है।
लॉर्डऑफइंप्ल्स

मैं भी के कार्यान्वयन की तुलना में किया है WebAppClassLoader.findResource(String name)में बिलाव 7 के साथ बिलाव 8 , और ऐसा लगता है एक मुख्य अंतर यह देखते हैं कि। टॉमकैट 8 स्पष्ट रूप से एक अग्रणी जोड़कर संसाधन नाम को सामान्य /करता है यदि इसमें कोई भी शामिल नहीं है, जो सभी नामों को निरपेक्ष बनाता है। टॉमकैट 7 नहीं। यह स्पष्ट रूप से टॉमकैट 7 में एक बग है
लॉर्डऑफThePigs

मैंने अपने उत्तर में इसके बारे में एक पैराग्राफ जोड़ा।
लॉर्डऑफइंपल्स

0

बिना किसी सफलता के साथ फ़ाइल को लोड करने के कुछ तरीकों की कोशिश करने के बाद, मुझे याद आया कि मैं इसका उपयोग कर सकता हूं FileInputStream, जो पूरी तरह से काम करता है।

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

यह एक फ़ाइल को एक में पढ़ने का एक और तरीका है InputStream, यह वर्तमान में चल रहे फ़ोल्डर से फ़ाइल को पढ़ता है।


यह एक फाइल नहीं है, यह एक संसाधन है। उत्तर सही नहीं है।
लोर्ने

1
@EJP मैं इस SO उत्तर में फाइल और संसाधन के बीच अंतर को जाने बिना, फ़ाइल लोड करने के तरीके खोज रहा हूं। मैं अपना उत्तर नहीं हटाने जा रहा हूँ क्योंकि इससे दूसरों को मदद मिल सकती है।
एंटोनियो अल्मेडा

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.