জাভাতে রিসোর্স লোড করার পছন্দের উপায়


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 ইউটিউলে getResource থেকে ফিরে কেবল "ওপেনস্ট্রিম" কল করে এবং এটি ফেরত দেয়।


আফাইক প্যাকেজগুলির নামগুলি কোনও ব্যাপার নয়, এটি শ্রেণি লোডের শ্রেণিপথ।
বার্ট ভ্যান হিউকেলোম

@ বার্ট যদি আপনি সোর্স কোডটি দেখেন তবে আপনি খেয়াল করবেন যে ক্লাসে getResource কল করার সময় শ্রেণীর নামটি গুরুত্বপূর্ণ। এই কলটি প্রথম যেটি করে তা হ'ল "রেজালিউশন" যা উপযুক্ত হলে প্যাকেজ উপসর্গ যুক্ত করে। রেজোলিউশনের নাম জাভাদোক হ'ল নামটি যদি নিখুঁত না হয় তবে একটি প্যাকেজ নামের উপসর্গ যুক্ত করুন "/" নাম যদি নিখুঁত হয় তবে "
মাইকেল ওয়াইলস

10
আহ আমি দেখি. সম্পূর্ণরূপে এখানে ফাইল সিস্টেমের পরম নয় বরং শ্রেণিপথের সাথে সম্পর্কিত।
বার্ট ভ্যান হিউকেলোম

1
আমি কেবল যুক্ত করতে চাই যে আপনার সর্বদা পরীক্ষা করা উচিত যে getResourceAsStream () থেকে ফিরে আসা স্ট্রিমটি নাল নয়, কারণ এটি যদি উত্সটি ক্লাসপাথের মধ্যে না থাকে।
স্টেনিক্স

আরও লক্ষণীয় যে প্রসঙ্গ বর্গ লোডার ব্যবহার করে ক্লাস লোডারটি রানটাইম সময়ে রান-এর মাধ্যমে পরিবর্তন করা যায় Thread#setContextClassLoader। প্রোগ্রামটি সঞ্চালনের সময় আপনার ক্লাসপথটি সংশোধন করতে হবে তবে এটি কার্যকর।
সর্বোচ্চ

14

ঠিক আছে, এটি আংশিকভাবে নির্ভর করে যদি আপনি আসলে একটি উদ্ভূত শ্রেণিতে থাকেন তবে আপনি কী হতে চান ।

উদাহরণস্বরূপ, ধরুন SuperClassএজারে এবং SubClassবিজারে রয়েছে এবং আপনি ঘোষিত একটি উদাহরণ পদ্ধতিতে কোড সম্পাদন করছেন SuperClassতবে যেখানে thisউদাহরণটির উল্লেখ রয়েছে SubClass। আপনি যদি this.getClass().getResource()এটি ব্যবহার করেন তবে এটি SubClassবিজারের সাথে সম্পর্কিত হবে। আমার সন্দেহ হয় যা সাধারণত প্রয়োজন হয় না।

ব্যক্তিগতভাবে আমি সম্ভবত Foo.class.getResourceAsStream(name)প্রায়শই ব্যবহার করতাম - যদি আপনি ইতিমধ্যে নিজের যে সংস্থানটি পরেছেন তার নামটি যদি আপনি জানতে থাকেন এবং এটি কোথায় সম্পর্কিত তবে আপনি অবশ্যই নিশ্চিত হন Fooযে এটি আইএমও করার সবচেয়ে শক্তিশালী উপায়।

অবশ্যই এমন সময় রয়েছে যখন আপনি যা চান তাও নয় : প্রতিটি মামলার গুণাবলী বিবেচনা করুন। এটি কেবলমাত্র "আমি জানি এই সংস্থানটি এই শ্রেণীর সাথে একত্রিত করা হয়েছে" এটি সর্বাধিক সাধারণ যা আমি প্রবেশ করেছি।


স্কিট: বিবৃতিতে সন্দেহ "আপনি সুপারক্লাসের উদাহরণ পদ্ধতিতে কোড প্রয়োগ করছেন তবে যেখানে এটি সাবক্লাসের একটি উদাহরণকে বোঝায়" যদি আমরা সুপার ক্লাসের উদাহরণ পদ্ধতির অভ্যন্তরে বিবৃতিগুলি প্রয়োগ করি তবে "এই" সুপারক্লাসকে উল্লেখ করবে না সাবক্লাস।
ডেড প্রোগ্রামার

1
@ সুরেশ: না তা হবে না। চেষ্টা করে দেখুন! দুটি ক্লাস তৈরি করুন, একটি থেকে অন্যটি তৈরি করে এবং তারপরে সুপারক্লাসের প্রিন্ট আউটে this.getClass()। সাবক্লাসের একটি উদাহরণ তৈরি করুন এবং পদ্ধতিটি কল করুন ... এটি সাবক্লাসের নাম মুদ্রণ করবে, সুপারক্লাস নয়।
জন স্কিটি

ধন্যবাদ সাবক্লাস উদাহরণ পদ্ধতি সুপারক্লাসের পদ্ধতিটিকে কল করে।
ডেড প্রোগ্রামার

1
আমি যা ভাবছি তা হ'ল এটি.বিটআর রিসোর্সএস্ট্রিস্ট ব্যবহার করা কেবল এই জার থেকে কোনও সংস্থান লোড করতে সক্ষম হবে যেহেতু এই সংঘর্ষটি অন্য জার থেকে নয়। আমার হিসেব অনুসারে, এটি ক্লাস লোডার যা সংস্থানটি লোড করে এবং অবশ্যই কেবল একটি জার থেকে লোডিংয়ের মধ্যে আবদ্ধ হবে না?
মাইকেল ওয়াইলস

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 টি আলাদা জায়গা থেকে ফাইল লোড করতে চান তা পাই না। আপনি জানেন না আপনার ফাইলগুলি কোথায় সঞ্চিত আছে?
বিভিডিবি

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

@ প্রম কমপট, যেমনটি আমি বলেছি this.getClass().getResourceAsStream()আমার পক্ষে কাজ করে না, তাই আমি সেই কাজগুলি ব্যবহার করি। আমি মনে করি এমন কিছু লোক আছেন যারা আমার মতো সমস্যার মুখোমুখি হতে পারেন।
ভ্লাদিস্লাভ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.