जावा में संसाधन लोड करने का पसंदीदा तरीका


107

मैं जावा में संसाधन लोड करने का सबसे अच्छा तरीका जानना चाहता हूं:

  • this.getClass().getResource() (or getResourceAsStream()),
  • Thread.currentThread().getContextClassLoader().getResource(name),
  • System.class.getResource(name)

जवाबों:


140

आप जो चाहते हैं उसी के अनुसार समाधान निकालें ...

वहाँ दो चीजें हैं जो कर रहे हैं getResource/ getResourceAsStream()वर्ग इस पर कहा जाता है से मिलेगा ...

  1. वर्ग लोडर
  2. प्रारंभिक स्थान

इसलिए यदि आप

this.getClass().getResource("foo.txt");

यह foo.txt को "इस" वर्ग के समान पैकेज से और "इस" वर्ग के क्लास लोडर के साथ लोड करने का प्रयास करेगा। यदि आप सामने "/" डालते हैं तो आप संसाधन का संदर्भ दे रहे हैं।

this.getClass().getResource("/x/y/z/foo.txt")

"लोड" और xyz पैकेज के वर्ग लोडर से संसाधन को लोड करेगा (इसे उस पैकेज में कक्षाओं के समान निर्देशिका में होना होगा)।

Thread.currentThread().getContextClassLoader().getResource(name)

संदर्भ वर्ग लोडर के साथ लोड होगा, लेकिन किसी भी पैकेज के अनुसार नाम का समाधान नहीं करेगा (यह बिल्कुल संदर्भित होना चाहिए)

System.class.getResource(name)

सिस्टम क्लास लोडर के साथ संसाधन को लोड करेगा (इसे पूरी तरह से संदर्भित करना होगा, क्योंकि आप java.lang पैकेज (सिस्टम के पैकेज) में कुछ भी नहीं डाल पाएंगे।

बस स्रोत पर एक नज़र रखना। यह भी इंगित करता है कि getResourceAsStream केवल URL पर "openStream" कॉल करता है जो getResource से लौटा है और जो लौटाता है।


AFAIK पैकेज नाम मायने नहीं रखते, यह क्लास लोडर का क्लासपैथ है जो करता है।
बजे बार्ट वैन ह्युकेलोम

@Bart यदि आप स्रोत कोड को देखते हैं, तो आप देखेंगे कि जब आप क्लास पर getResource कहते हैं तो क्लास का नाम मायने रखता है। पहली बात यह है कि कॉल "समाधाननाम" है जो उचित होने पर पैकेज उपसर्ग जोड़ता है। समाधान के लिए Javadoc है "नाम जोड़ें उपसर्ग जोड़ें यदि नाम निरपेक्ष नहीं है तो हटाएं अग्रणी" / "यदि नाम निरपेक्ष है"
माइकल विल्स

10
ओह समझा। यहाँ निरपेक्ष का अर्थ है क्लासपास के सापेक्ष, बजाय फाइलसिस्टम निरपेक्ष।
बजे बार्ट वैन ह्युकेलोम

1
मैं केवल यह जोड़ना चाहता हूं कि आपको हमेशा यह जांचना चाहिए कि स्ट्रीम getResourceAsStream () से वापस आ गई है या नहीं, क्योंकि यह ऐसा नहीं है क्योंकि संसाधन वर्गपथ के भीतर नहीं है।
स्टेनिक्स

यह भी ध्यान देने योग्य है कि संदर्भ क्लास लोडर का उपयोग करके क्लास लोडर को रनटाइम के माध्यम से बदलने की अनुमति मिलती है Thread#setContextClassLoader। यह उपयोगी है यदि आपको प्रोग्राम निष्पादित करते समय क्लासपाथ को संशोधित करने की आवश्यकता है।
अधिकतम

14

ठीक है, यह आंशिक रूप से निर्भर करता है कि आप क्या करना चाहते हैं यदि आप वास्तव में एक व्युत्पन्न वर्ग में हैं।

उदाहरण के लिए, मान लें कि SuperClassएज़ेर में है और SubClassB.jar में है, और आप एक इंस्टेंस विधि में कोड निष्पादित कर रहे हैं, SuperClassलेकिन जहां thisएक इंस्टेंस को संदर्भित करता है SubClass। यदि आप इसका उपयोग this.getClass().getResource()करते हैं SubClass, तो B.jar में इसके सापेक्ष दिखेगा । मुझे संदेह है कि आमतौर पर है वह नहीं है जिसकी आवश्यकता है।

व्यक्तिगत रूप से मैं शायद Foo.class.getResourceAsStream(name)सबसे अधिक बार उपयोग करूंगा - यदि आप पहले से ही उस संसाधन का नाम जानते हैं जो आप के बाद का है, और आप निश्चित हैं कि यह कहां के सापेक्ष है Foo, तो यह आईएमओ करने का सबसे मजबूत तरीका है।

बेशक कई बार जब वह नहीं आप क्या चाहते हैं, भी: अपनी योग्यता के आधार पर प्रत्येक मामले न्यायाधीश। यह सिर्फ "मुझे पता है कि यह संसाधन इस वर्ग से जुड़ा हुआ है" सबसे आम है जिसे मैंने चलाया है।


स्कीट: स्टेटमेंट में एक संदेह "आप सुपरक्लास के इंस्टेंस मेथड में कोड निष्पादित कर रहे हैं, लेकिन जहां यह सबक्लास के इंस्टेंस को संदर्भित करता है" उपवर्ग।
डेड प्रोग्रामर

1
@ सुरेश: नहीं, यह नहीं होगा। कोशिश करो! दो कक्षाएं बनाएं, एक दूसरे से व्युत्पन्न करें, और फिर सुपरक्लास प्रिंट आउट में this.getClass()। उपवर्ग का एक उदाहरण बनाएं और विधि को कॉल करें ... यह उपवर्ग का नाम प्रिंट करेगा, न कि सुपरक्लास।
जॉन स्कीट

धन्यवाद उपवर्ग उदाहरण विधि सुपरक्लास की विधि कहती है।
मृत प्रोग्रामर

1
मैं इस बारे में सोच रहा हूँ कि क्या यह प्रयोग कर रहा है ।getResourceAsStream केवल उसी जार से एक संसाधन लोड करने में सक्षम होगा, क्योंकि यह क्लैस दूसरे जार से है और नहीं। मेरे हिसाब से, यह क्लास लोडर है जो संसाधन को लोड करता है और निश्चित रूप से केवल एक जार से लोड करने से सीमित नहीं होगा?
माइकल विल्स

10

मैं तीन स्थानों की खोज करता हूं जैसा कि नीचे दिखाया गया है। टिप्पणियाँ स्वागत है।

public URL getResource(String resource){

    URL url ;

    //Try with the Thread Context Loader. 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Let's now try with the classloader that loaded this class.
    classLoader = Loader.class.getClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Last ditch attempt. Get the resource from the classpath.
    return ClassLoader.getSystemResource(resource);
}

धन्यवाद, यह एक महान विचार है। मुझे जिस चीज की जरूरत थी।
देवो

2
मैं आपके कोड में टिप्पणियों को देख रहा था और अंतिम एक दिलचस्प लगता है। क्या सभी संसाधन वर्गपथ से लोड नहीं हैं? और क्या मामले होते हैं ClassLoader.getSystemResource () कवर जो ऊपर सफल नहीं हुआ?
nyxz

सभी ईमानदारी में, मुझे नहीं लगता कि आप 3 अलग-अलग जगहों से फाइलें क्यों लोड करना चाहते हैं। क्या आप नहीं जानते कि आपकी फ़ाइलें कहाँ संग्रहीत हैं?
bvdb

3

मुझे पता है कि यह वास्तव में एक और जवाब के लिए देर हो चुकी है, लेकिन मैं सिर्फ वही साझा करना चाहता था जिसने आखिर में मेरी मदद की। यह फ़ाइल सिस्टम के पूर्ण पथ (न केवल क्लासपैथ के) से संसाधनों / फ़ाइलों को लोड करेगा।

public class ResourceLoader {

    public static URL getResource(String resource) {
        final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
        classLoaders.add(Thread.currentThread().getContextClassLoader());
        classLoaders.add(ResourceLoader.class.getClassLoader());

        for (ClassLoader classLoader : classLoaders) {
            final URL url = getResourceWith(classLoader, resource);
            if (url != null) {
                return url;
            }
        }

        final URL systemResource = ClassLoader.getSystemResource(resource);
        if (systemResource != null) {
            return systemResource;
        } else {
            try {
                return new File(resource).toURI().toURL();
            } catch (MalformedURLException e) {
                return null;
            }
        }
    }

    private static URL getResourceWith(ClassLoader classLoader, String resource) {
        if (classLoader != null) {
            return classLoader.getResource(resource);
        }
        return null;
    }

}

0

मैंने बहुत सारे तरीके और फ़ंक्शन आज़माए, जो ऊपर दिए गए थे, लेकिन उन्होंने मेरे प्रोजेक्ट में काम नहीं किया। वैसे भी मुझे समाधान मिल गया है और यहाँ यह है:

try {
    InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
    img = ImageIO.read(path);
} catch (IOException e) {
    e.printStackTrace();
}

आपको this.getClass().getResourceAsStream()इस मामले में बेहतर उपयोग करना चाहिए । यदि आप getResourceAsStreamविधि के स्रोत पर एक नज़र डालते हैं , तो आप देखेंगे कि यह आपकी तुलना में एक ही काम करता है लेकिन एक बेहतर तरीके से (यदि ClassLoaderकक्षा में कोई भी नहीं पाया जा सकता है)। यह भी पता चलता है कि आप एक संभावित सामना कर सकते हैं nullपर getClassLoaderअपने कोड में ...
डॉक्टर Davluz

@PromCompot, जैसा कि मैंने कहा कि this.getClass().getResourceAsStream()मेरे लिए काम नहीं कर रहा है, इसलिए मैं उस काम का उपयोग करता हूं। मुझे लगता है कि कुछ लोग हैं जो मेरी जैसी समस्या का सामना कर सकते हैं।
व्लादिस्लाव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.