जार के भीतर से संसाधन फ़ाइल पढ़ना


242

मैं अपने जार के भीतर से एक संसाधन पढ़ना चाहूंगा जैसे:

File file;
file = new File(getClass().getResource("/file.txt").toURI());
BufferredReader reader = new BufferedReader(new FileReader(file));

//Read the file

और यह ग्रहण में चलने पर ठीक काम करता है, लेकिन अगर मैं इसे एक जार में निर्यात करता हूं तो यह रन अवैध है।

Exception in thread "Thread-2"
java.lang.IllegalArgumentException: URI is not hierarchical

और मैं वास्तव में नहीं जानता कि क्यों कुछ परीक्षण के साथ मैंने पाया कि अगर मैं बदलता हूं

file = new File(getClass().getResource("/file.txt").toURI());

सेवा

file = new File(getClass().getResource("/folder/file.txt").toURI());

तब यह विपरीत काम करता है (यह जार में काम करता है लेकिन ग्रहण नहीं करता है)।

मैं ग्रहण का उपयोग कर रहा हूं और मेरी फ़ाइल वाला फ़ोल्डर एक क्लास फ़ोल्डर में है।


यदि आप फ़ाइलों के लिए किसी भी संख्या के साथ जार में निर्देशिका से फ़ाइलों को पढ़ना चाहते हैं, तो Stackoverflow-Link
माइकल हेगनर

1
मुझे यकीन नहीं है कि मूल प्रश्न वसंत शामिल था। पिछली टिप्पणी में लिंक एक अलग सवाल से वसंत विशिष्ट उत्तर को संदर्भित करता है। मेरा मानना getResourceAsStreamहै कि अभी भी समस्या का एक सरल और अधिक पोर्टेबल समाधान है।
आकर्षित MacInnis

जवाबों:


398

बल्कि एक के रूप में संसाधन संबोधित करने के लिए कोशिश कर रहा से फाइल सिर्फ पूछना classloader एक वापस जाने के लिए InputStream के माध्यम से के बजाय संसाधन के लिए getResourceAsStream :

InputStream in = getClass().getResourceAsStream("/file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

जब तक file.txtसंसाधन वर्गपथ पर उपलब्ध है, तब तक यह तरीका उसी तरह से काम करेगा, भले ही file.txtसंसाधन classes/निर्देशिका में हो या अंदर jar

URI is not hierarchicalइसलिए होती है क्योंकि एक जार फ़ाइल के भीतर एक संसाधन के लिए यूआरआइ इस तरह देखो दे रहा है: file:/example.jar!/file.txt। आप एक jar(एक zipफ़ाइल) के भीतर प्रविष्टियों को नहीं पढ़ सकते हैं जैसे कि यह एक पुरानी पुरानी फ़ाइल थी

इसका उत्तर अच्छी तरह से समझाया गया है:


3
धन्यवाद, यह बहुत मददगार था और कोड पूरी तरह से काम करता है, लेकिन मुझे एक समस्या है, मुझे यह निर्धारित करने की आवश्यकता है कि क्या InputStreamमौजूद है (जैसे File.exists()) इसलिए मेरा गेम बता सकता है कि क्या डिफ़ॉल्ट फ़ाइल का उपयोग करना है या नहीं। धन्यवाद।
प्रिंस

1
ओह और BTW कारण getClass().getResource("**/folder**/file.txt")यह काम किया है, क्योंकि मैं उस फ़ोल्डर मेरे जार के रूप में एक ही निर्देशिका में था :)।
प्रिंससीजेसी

5
getResourceAsStreamयदि संसाधन मौजूद नहीं है, तो यह अशक्त देता है कि आपका "अस्तित्व" परीक्षण हो सकता है।
MacInnis

1
BTW, आपके पास एक टाइपो है: यह बफ़रड्रेडर होना चाहिए, बफ़रड्रेडर नहीं (बाद में अतिरिक्त 'आर' पर ध्यान दें)
मेलमाइन्डलिन

2
और निश्चित रूप से ... InputStream और BufferedReader को बंद करना न भूलें
Noremac

26

किसी फ़ाइल को जार में एक्सेस करने के लिए आपके पास दो विकल्प हैं:

  • अपने पैकेज के नाम से मेल खाने वाली निर्देशिका संरचना में फ़ाइल रखें (.jar फ़ाइल को निकालने के बाद, यह .class फ़ाइल के समान निर्देशिका में होनी चाहिए), फिर इसका उपयोग करके उपयोग करें। getClass().getResourceAsStream("file.txt")

  • फ़ाइल को रूट पर रखें (.jar फ़ाइल निकालने के बाद, यह रूट में होना चाहिए), फिर इसका उपयोग करके एक्सेस करें Thread.currentThread().getContextClassLoader().getResourceAsStream("file.txt")

जब जार एक प्लगइन के रूप में उपयोग किया जाता है तो पहला विकल्प काम नहीं कर सकता है।


इस शानदार उत्तर के लिए बहुत-बहुत धन्यवाद ... दूसरे विकल्प से एक और लाभ यह है कि यह मुख्य विधि से भी काम करता है, क्योंकि getClass () केवल एक उदाहरण से काम करता है और स्थिर तरीकों से नहीं।
Dan Ortega

6

मुझे पहले यह समस्या थी और मैंने लोडिंग के लिए वापसी का रास्ता बनाया। मूल रूप से पहला तरीका .jar फ़ाइल के भीतर काम करता है और दूसरा तरीका ग्रहण या अन्य आईडीई के भीतर काम करता है।

public class MyClass {

    public static InputStream accessFile() {
        String resource = "my-file-located-in-resources.txt";

        // this is the path within the jar file
        InputStream input = MyClass.class.getResourceAsStream("/resources/" + resource);
        if (input == null) {
            // this is how we load file within editor (eg eclipse)
            input = MyClass.class.getClassLoader().getResourceAsStream(resource);
        }

        return input;
    }
}

3

अब तक (दिसंबर 2017), यह एकमात्र समाधान है जो मैंने पाया जो आईडीई के अंदर और बाहर दोनों काम करता है ।

PathMatchingResourcePatternResolver का उपयोग करें

नोट: यह स्प्रिंग-बूट में भी काम करता है

इस उदाहरण में मैं src / main / Resources / my_folder में स्थित कुछ फाइलें पढ़ रहा हूं :

try {
    // Get all the files under this inner resource folder: my_folder
    String scannedPackage = "my_folder/*";
    PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
    Resource[] resources = scanner.getResources(scannedPackage);

    if (resources == null || resources.length == 0)
        log.warn("Warning: could not find any resources in this scanned package: " + scannedPackage);
    else {
        for (Resource resource : resources) {
            log.info(resource.getFilename());
            // Read the file content (I used BufferedReader, but there are other solutions for that):
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                // ...
                // ...                      
            }
            bufferedReader.close();
        }
    }
} catch (Exception e) {
    throw new Exception("Failed to read the resources folder: " + e.getMessage(), e);
}

3

समस्या यह है कि कुछ तीसरे पक्ष के पुस्तकालयों को इनपुट स्ट्रीम के बजाय फ़ाइल पाथने की आवश्यकता होती है। अधिकांश उत्तर इस समस्या का समाधान नहीं करते हैं।

इस स्थिति में, एक संसाधन एक अस्थायी फ़ाइल में संसाधन सामग्री की प्रतिलिपि बनाने के लिए है। निम्न उदाहरण jUnit का उपयोग करता है TemporaryFolder

    private List<String> decomposePath(String path){
        List<String> reversed = Lists.newArrayList();
        File currFile = new File(path);
        while(currFile != null){
            reversed.add(currFile.getName());
            currFile = currFile.getParentFile();
        }
        return Lists.reverse(reversed);
    }

    private String writeResourceToFile(String resourceName) throws IOException {
        ClassLoader loader = getClass().getClassLoader();
        InputStream configStream = loader.getResourceAsStream(resourceName);
        List<String> pathComponents = decomposePath(resourceName);
        folder.newFolder(pathComponents.subList(0, pathComponents.size() - 1).toArray(new String[0]));
        File tmpFile = folder.newFile(resourceName);
        Files.copy(configStream, tmpFile.toPath(), REPLACE_EXISTING);
        return tmpFile.getAbsolutePath();
    }

यह बहुत अधिक चमक रहा है। इसे प्रलेखित करने के लिए धन्यवाद। मैं उत्सुक हूं कि JUnit के बिना अन्य विकल्प क्या मौजूद हैं।
एलेक्स मूर-नीमी

0

यदि आप एक फ़ाइल के रूप में पढ़ना चाहते हैं, मेरा मानना ​​है कि अभी भी एक समान समाधान है:

    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("file/test.xml").getFile());

4
URL.getFile () URL को फ़ाइल नाम में परिवर्तित नहीं करता है । यह होस्ट के बाद URL के हिस्से को सभी प्रतिशत-एन्कोडिंग के साथ बरकरार रखता है, इसलिए यदि पथ में कोई भी गैर-ASCII वर्ण या कोई ASCII वर्ण URL (रिक्त स्थान सहित) की अनुमति नहीं है, तो परिणाम एक मौजूदा नाम नहीं होगा भले ही URL एक file:URL हो।
वीजीआर

48
एक बार कार्यक्रम के निर्माण के दौरान यह काम नहीं करता है
अक्षय कासर

1
जार से काम नहीं करता है जब तक आप स्ट्रिंग में परिवर्तित नहीं करते हैं और इसे स्थानीय रूप से पहले बचाते हैं।
smoosh911

0

सुनिश्चित करें कि आप सही विभाजक के साथ काम करते हैं। मैं /एक के साथ एक रिश्तेदार रास्ते में सभी को बदल दिया File.separator। इसने IDE में ठीक काम किया, हालांकि बिल्ड JAR में काम नहीं किया।


0

मुझे लगता है कि यह जावा में भी काम करना चाहिए। निम्न कोड जो मैं उपयोग कर रहा हूं वह कोटलिन का उपयोग कर रहा है।

val resource = Thread.currentThread().contextClassLoader.getResource('resources.txt')

0

मैंने एक फिक्स पाया है

BufferedReader br = new BufferedReader(new InputStreamReader(Main.class.getResourceAsStream(path)));

"मेन" को उस जावा क्लास से बदलें जिसमें आपने इसे कोडित किया है। जार फाइल के भीतर "पाथ" को पाथ से बदलें।

उदाहरण के लिए, यदि आप com.issac.state को पैकेज में State1.txt डालते हैं, तो लिनक्स या मैक चलाने पर "/ com / issac / state / State1" के रूप में पथ टाइप करें। यदि आप विंडोज चलाते हैं तो "\ com \ issac \ state \ State1" के रूप में पथ टाइप करें। जब तक फ़ाइल को अपवाद न मिले तब तक फ़ाइल में .txt एक्सटेंशन न जोड़ें।


-1

आप क्लास लोडर का उपयोग कर सकते हैं जो आरओटी पथ के रूप में क्लासपथ से पढ़ेगा (शुरुआत में "/" के बिना)

InputStream in = getClass().getClassLoader().getResourceAsStream("file.txt"); 
BufferedReader reader = new BufferedReader(new InputStreamReader(in));

-1

यदि आप वसंत का उपयोग कर रहे हैं, तो आप src / main / resource से फ़ाइल पढ़ने के लिए निम्न विधि का उपयोग कर सकते हैं:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.springframework.core.io.ClassPathResource;

  public String readFileToString(String path) throws IOException {

    StringBuilder resultBuilder = new StringBuilder("");
    ClassPathResource resource = new ClassPathResource(path);

    try (
        InputStream inputStream = resource.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {

      String line;

      while ((line = bufferedReader.readLine()) != null) {
        resultBuilder.append(line);
      }

    }

    return resultBuilder.toString();
  }

1
एसओ में आपका स्वागत है। यह प्रश्न का उत्तर प्रदान नहीं करता है। एक बार जब आपके पास पर्याप्त प्रतिष्ठा होगी तो आप किसी भी पोस्ट पर टिप्पणी कर पाएंगे । इसके अलावा मैं क्या कर सकता हूं इसकी जांच करें ।
द वेवेयेरे

यह फ़ाइल में लाइन ब्रेक को हटा देगा!
elad.chen

-1

किसी कारण से classLoader.getResource()मैं हमेशा अशक्त हो जाता हूं जब मैंने वेब एप्लिकेशन को WildFly 14 में तैनात किया था । null से classLoader प्राप्त getClass().getClassLoader()कर रहा था Thread.currentThread().getContextClassLoader()

getClass().getClassLoader() एपीआई डॉक्टर कहते हैं,

"क्लास के लिए क्लास लोडर लौटाता है। कुछ कार्यान्वयन बूटस्ट्रैप क्लास लोडर का प्रतिनिधित्व करने के लिए अशक्त का उपयोग कर सकते हैं। यह विधि ऐसे कार्यान्वयनों में शून्य वापस आ जाएगी यदि यह वर्ग बूटस्ट्रैप क्लास लोडर द्वारा लोड किया गया था।"

हो सकता है कि आप वाइल्डली और आपके वेब एप्लिकेशन का उपयोग कर रहे हों

request.getServletContext().getResource()संसाधन url लौटाया। यहाँ अनुरोध ServletRequest का एक उद्देश्य है।


-2

नीचे कोड स्प्रिंग बूट (कोटलिन) के साथ काम करता है:

val authReader = InputStreamReader(javaClass.getResourceAsStream("/file1.json"))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.