Java JAR फाइल में संसाधन के लिए रास्ता कैसे प्राप्त करें


166

मैं एक संसाधन के लिए एक रास्ता पाने की कोशिश कर रहा हूं लेकिन मुझे कोई भाग्य नहीं है।

यह काम करता है (दोनों IDE और JAR के साथ) लेकिन इस तरह से मुझे एक फ़ाइल का रास्ता नहीं मिल सकता है, केवल फ़ाइल सामग्री:

ClassLoader classLoader = getClass().getClassLoader();
PrintInputStream(classLoader.getResourceAsStream("config/netclient.p"));

अगर मैं ऐसा करता हूं:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("config/netclient.p").getFile());

परिणाम है: java.io.FileNotFoundException: file:/path/to/jarfile/bot.jar!/config/netclient.p (No such file or directory)

क्या संसाधन फ़ाइल के लिए एक रास्ता है?


1
हाँ। मुझे एक वर्ग मिला है जो मैं दोनों के साथ काम करना चाहूंगा, बाहर एक फ़ोल्डर (यदि मैं कॉन्फ़िगर फ़ाइल के कुछ पैरामीटर को बदलना चाहता हूं) और एक जार जो उपयोगकर्ता के लिए कार्यान्वयन कॉन्फ़िगरेशन फ़ाइलों को छुपाता है (एक वितरण योग्य की तरह) सभी लोगों को JAR)।
no_ripcord

1
इसलिए कक्षा को केवल एक फाइल (कॉन्फिग फाइल) के लिए एक पाथ प्राप्त होता है।
no_ripcord

3
तब आपके पास संभवतः इनपुट स्ट्रीम के साथ वह क्लास डील होनी चाहिए, जिसे आप स्रोत से प्राप्त कर सकते हैं।
कार्ल मैनस्टर

1
हाँ मैं जानता हूँ। लेकिन यह अधिक स्पष्ट और दूसरे तरीके से साफ होता। लेकिन thx वैसे भी।
no_ripcord

1
क्या आप इस प्रश्न में विकल्प # 4 जैसा कुछ करने की कोशिश कर रहे हैं? stackoverflow.com/questions/775389/…
इरिकसन

जवाबों:


71

यह जानबूझकर है। "फ़ाइल" की सामग्री फ़ाइल के रूप में उपलब्ध नहीं हो सकती है। याद रखें कि आप उन कक्षाओं और संसाधनों के साथ काम कर रहे हैं जो JAR फ़ाइल या अन्य प्रकार के संसाधन का हिस्सा हो सकते हैं। क्लास लोडर को संसाधन के लिए फ़ाइल हैंडल प्रदान करने की आवश्यकता नहीं होती है, उदाहरण के लिए जार फ़ाइल को फ़ाइल सिस्टम में व्यक्तिगत फ़ाइलों में विस्तारित नहीं किया जा सकता है।

Java.io.File प्राप्त करके आप जो कुछ भी कर सकते हैं, वह एक अस्थायी फ़ाइल में स्ट्रीम को कॉपी करके और एक ही कर सकता है, अगर एक java.io.File बिल्कुल आवश्यक है।


6
जब आप इसे खोलने के लिए अपने संसाधन को जोड़ते हैं तो आप 'rsrc:' जोड़ सकते हैं। नई फ़ाइल की तरह ("rsrc: filename.txt") यह filename.txt को लोड करेगा जो आपके जार के रूट के अंदर पैक किया गया है
gipsh

63

संसाधन लोड करते समय सुनिश्चित करें कि आप निम्नलिखित के बीच अंतर देखते हैं:

getClass().getClassLoader().getResource("com/myorg/foo.jpg") //relative path

तथा

getClass().getResource("/com/myorg/foo.jpg")); //note the slash at the beginning

मुझे लगता है, संसाधन को लोड करते समय यह भ्रम सबसे अधिक समस्याएं पैदा कर रहा है।


इसके अलावा, जब आप एक छवि लोड कर रहे हैं तो इसका उपयोग करना आसान है getResourceAsStream():

BufferedImage image = ImageIO.read(getClass().getResourceAsStream("/com/myorg/foo.jpg"));

जब आपको वास्तव में JAR संग्रह से एक (गैर-छवि) फ़ाइल लोड करनी हो, तो आप यह कोशिश कर सकते हैं:

File file = null;
String resource = "/com/myorg/foo.xml";
URL res = getClass().getResource(resource);
if (res.getProtocol().equals("jar")) {
    try {
        InputStream input = getClass().getResourceAsStream(resource);
        file = File.createTempFile("tempfile", ".tmp");
        OutputStream out = new FileOutputStream(file);
        int read;
        byte[] bytes = new byte[1024];

        while ((read = input.read(bytes)) != -1) {
            out.write(bytes, 0, read);
        }
        out.close();
        file.deleteOnExit();
    } catch (IOException ex) {
        Exceptions.printStackTrace(ex);
    }
} else {
    //this will probably work in your IDE, but not from a JAR
    file = new File(res.getFile());
}

if (file != null && !file.exists()) {
    throw new RuntimeException("Error: File " + file + " not found!");
}

3
+1 यह मेरे लिए काम कर गया। सुनिश्चित करें कि आप उन फ़ाइलों को रखते हैं जिन्हें आप binफ़ोल्डर में पढ़ना चाहते हैं और `/com/myorg/filename.ext 'पथ का उपयोग करने से पहले संसाधनों में वर्ग लोडिंग की निर्देशिका पर जाएं।
रेयिरेंग

+1 यह मेरे लिए भी काम करता है ... मैं समझता हूं कि इस दृष्टिकोण से संबंधित कुछ सुरक्षा जोखिम हो सकते हैं, इसलिए एप्लिकेशन मालिकों को इसके बारे में पता होना चाहिए।
लुकासा

क्या आप इस कथन को स्पष्ट कर सकते हैं "getResourceAsStream ()" के साथ संसाधन लोड करना हमेशा बेहतर होता है? यह समस्या का समाधान कैसे प्रदान कर सकता है?
लुका एस।

@LucaS। यह सिर्फ छवियों के मामले के लिए था, क्षमा करें यह बहुत स्पष्ट नहीं था। दृष्टिकोण प्लेटफ़ॉर्म स्वतंत्र होना चाहिए, हालांकि यह थोड़ा हैकी तरीका है।
टॉम्बर्ट

@ लुकासा क्या आप अपने द्वारा बताए गए जोखिमों को स्पष्ट कर सकते हैं?
ZX9

25

एक पंक्ति का उत्तर है -

String path = this.getClass().getClassLoader().getResource(<resourceFileName>).toExternalForm()

मूल रूप से getResourceविधि URL देता है। इस URL से आप कॉल करके रास्ता निकाल सकते हैंtoExternalForm()

संदर्भ:

getResource () , toExternalForm ()


7
मेरे वातावरण (IntelliJ) से चलने के दौरान यह एक साधारण फ़ाइल URL का उत्पादन करता है जो सभी मामलों में काम करता है। हालाँकि, जब जार से ही चल रहा होता है, तो मुझे जार के समान एक URI मिलता है: फ़ाइल: /path/to/jar/jarname.jar! /File_in_jar.mp4। सब कुछ एक यूआरआई का उपयोग नहीं कर सकता है जो जार से शुरू होता है। बिंदु JavaFX मीडिया में मामला।
नूह टेरनुलो

1
मुझे यह उत्तर सबसे अच्छा लगा। दी, ज्यादातर मामलों में जब यह एक जार फ़ाइल में है, तो यह केवल इनपुटस्ट्रीम को संसाधन में ले जाना बेहतर हो सकता है, लेकिन अगर किसी कारण से आपको वास्तव में पथ की आवश्यकता होती है, तो यह काम करता है। मुझे तृतीय-पक्ष ऑब्जेक्ट को देने के लिए पथ की आवश्यकता थी। तो धन्यवाद!
मारियो

1
उपरोक्त समाधान IDE में काम नहीं करता है, जबकि Intellijit file:/पथ में जुड़ जाता है, जो जार में काम करता है, लेकिन IDE में नहीं
तैयब हुसैन

आपकी प्रतिक्रिया से एक समस्या हल हो गई जो मैं कम से कम 2 दिनों से काम करने की कोशिश कर रहा था। TYVM !!
जोनाथन

12

मैंने इस समस्या के साथ खिलवाड़ करते हुए कुछ समय बिताया, क्योंकि कोई भी समाधान मुझे वास्तव में काम नहीं मिला, काफी अजीब था! कामकाजी निर्देशिका अक्सर JAR की निर्देशिका नहीं होती है, खासकर अगर JAR (या उस मामले के लिए कोई भी कार्यक्रम) विंडोज के तहत स्टार्ट मेनू से चलाया जाता है। तो यहाँ मैंने क्या किया है, और यह एक JAR के बाहर से चलने वाली .class फ़ाइलों के लिए काम करता है और साथ ही यह एक JAR के लिए भी काम करता है। (मैंने केवल विंडोज 7 के तहत इसका परीक्षण किया)

try {
    //Attempt to get the path of the actual JAR file, because the working directory is frequently not where the file is.
    //Example: file:/D:/all/Java/TitanWaterworks/TitanWaterworks-en.jar!/TitanWaterworks.class
    //Another example: /D:/all/Java/TitanWaterworks/TitanWaterworks.class
    PROGRAM_DIRECTORY = getClass().getClassLoader().getResource("TitanWaterworks.class").getPath(); // Gets the path of the class or jar.

    //Find the last ! and cut it off at that location. If this isn't being run from a jar, there is no !, so it'll cause an exception, which is fine.
    try {
        PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('!'));
    } catch (Exception e) { }

    //Find the last / and cut it off at that location.
    PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(0, PROGRAM_DIRECTORY.lastIndexOf('/') + 1);
    //If it starts with /, cut it off.
    if (PROGRAM_DIRECTORY.startsWith("/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(1, PROGRAM_DIRECTORY.length());
    //If it starts with file:/, cut that off, too.
    if (PROGRAM_DIRECTORY.startsWith("file:/")) PROGRAM_DIRECTORY = PROGRAM_DIRECTORY.substring(6, PROGRAM_DIRECTORY.length());
} catch (Exception e) {
    PROGRAM_DIRECTORY = ""; //Current working directory instead.
}

8

अगर netclient.pएक JAR फाइल के अंदर है, तो इसका कोई रास्ता नहीं होगा क्योंकि वह फाइल दूसरी फाइल के अंदर स्थित है। उस मामले में, आपके पास सबसे अच्छा रास्ता वास्तव में हो सकता है file:/path/to/jarfile/bot.jar!/config/netclient.p


जब मैं इस फॉर्मेट के URL (... bot.jar! / Config / ...) को URI में परिवर्तित करने का प्रयास करता हूँ तो यह कहता है कि यह मार्ग पदानुक्रमित नहीं है।
जीरिंगर

7

आपको जार फ़ाइल के भीतर पथ को समझने की आवश्यकता है।
बस इसे रिश्तेदार के रूप में देखें। इसलिए यदि आपके पास एक फ़ाइल (myfile.txt) है, जो \src\main\resourcesनिर्देशिका ( मावेन शैली) के तहत foo.jar में स्थित है । आप इसका उल्लेख इस तरह करेंगे:

src/main/resources/myfile.txt

यदि आप अपने जार को डंप करते हैं, तो आप jar -tvf myjar.jar जार फ़ाइल के भीतर आउटपुट और संबंधित पथ देखेंगे, और FORWARD SLASHES का उपयोग करें।


आपको वास्तव में आगे के स्लैश का उपयोग करना होगा, यहां तक ​​कि विंडोज पर भी। इसका मतलब है कि आप उपयोग नहीं कर सकते हैं File.separator
str

3

मेरे मामले में, मैंने पथ के बजाय URL ऑब्जेक्ट का उपयोग किया है।

फ़ाइल

File file = new File("my_path");
URL url = file.toURI().toURL();

क्लास लोडर का उपयोग करके क्लासपाथ में संसाधन

URL url = MyClass.class.getClassLoader().getResource("resource_name")

जब मुझे सामग्री पढ़ने की आवश्यकता होती है, तो मैं निम्नलिखित कोड का उपयोग कर सकता हूं:

InputStream stream = url.openStream();

और आप InputStream का उपयोग करके सामग्री तक पहुँच सकते हैं।


3

यह जार कोड से अपूर्ण अस्थायी फ़ाइल सामग्री प्रतिलिपि से बचने और अद्वितीय अस्थायी फ़ाइल नाम रखने के लिए स्ट्रीम फ्लश के साथ उपयोगकर्ता टॉम्बर्ट से समान कोड है।

File file = null;
String resource = "/view/Trial_main.html" ;
URL res = getClass().getResource(resource);
if (res.toString().startsWith("jar:")) {
    try {
        InputStream input = getClass().getResourceAsStream(resource);
        file = File.createTempFile(new Date().getTime()+"", ".html");
        OutputStream out = new FileOutputStream(file);
        int read;
        byte[] bytes = new byte[1024];

        while ((read = input.read(bytes)) != -1) {
            out.write(bytes, 0, read);
        }
        out.flush();
        out.close();
        input.close();
        file.deleteOnExit();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
} else {
    //this will probably work in your IDE, but not from a JAR
    file = new File(res.getFile());
}
         

2

एक फ़ाइल एक फ़ाइल सिस्टम में एक फ़ाइल के लिए एक अमूर्त है, और फाइल सिस्टम को इस बारे में कुछ भी पता नहीं है कि JAR की सामग्री क्या है।

एक URI के साथ प्रयास करें, मुझे लगता है कि एक जार है: // प्रोटोकॉल जो आपके purpouses के लिए उपयोगी हो सकता है।



1
private static final String FILE_LOCATION = "com/input/file/somefile.txt";

//Method Body


InputStream invalidCharacterInputStream = URLClassLoader.getSystemResourceAsStream(FILE_LOCATION);

इससे प्राप्त getSystemResourceAsStreamकरना सबसे अच्छा विकल्प है। फ़ाइल या URL के बजाय इनपुटस्ट्रीम प्राप्त करके, JAR फ़ाइल में और अकेले खड़े होने के रूप में काम करता है।


1

यह थोड़ी देर हो सकती है लेकिन आप अपने जार से एक संसाधन प्राप्त करने के लिए मेरी लाइब्रेरी KResourceLoader का उपयोग कर सकते हैं :

File resource = getResource("file.txt")

0

जब एक जार फ़ाइल में, संसाधन पैकेज पदानुक्रम (फ़ाइल सिस्टम पदानुक्रम नहीं) में बिल्कुल स्थित है। इसलिए यदि आपके पास "./default.conf" नामक संसाधन लोड करने के लिए वर्ग com.example.Sweet है, तो संसाधन का नाम "/com/example/default.conf" के रूप में निर्दिष्ट किया गया है।

लेकिन अगर यह जार में है तो यह फाइल नहीं है ...


0

आपके जार के आपके रिसोर्स फोल्डर (जावा / मेन / रिसोर्सेज) के अंदर आपकी फाइल को जोड़ते हैं (हम मानते हैं कि आपने एक xml फाइल इंपोर्टेस .xml नाम से जोड़ दी है ), उसके बाद ResourceLoaderअगर आप स्प्रिंग जैसे बेलो का इस्तेमाल करते हैं तो आप उसे इंजेक्ट करते हैं।

@Autowired
private ResourceLoader resourceLoader;

फ़ाइल को लोड करने के लिए टूर फंक्शन के अंदर bellow कोड लिखें:

    Resource resource = resourceLoader.getResource("classpath:imports.xml");
    try{
        File file;
        file = resource.getFile();//will load the file
...
    }catch(IOException e){e.printStackTrace();}

0

शायद इस विधि का उपयोग त्वरित समाधान के लिए किया जा सकता है।

public class TestUtility
{ 
    public static File getInternalResource(String relativePath)
    {
        File resourceFile = null;
        URL location = TestUtility.class.getProtectionDomain().getCodeSource().getLocation();
        String codeLocation = location.toString();
        try{
            if (codeLocation.endsWith(".jar"){
                //Call from jar
                Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
                resourceFile = path.toFile();
            }else{
                //Call from IDE
                resourceFile = new File(TestUtility.class.getClassLoader().getResource(relativePath).getPath());
            }
        }catch(URISyntaxException ex){
            ex.printStackTrace();
        }
        return resourceFile;
    }
}

क्या आप कुछ संदर्भ छोड़ रहे हैं? यह मुझे देता है:java.lang.NullPointerException: Attempt to invoke virtual method 'java.security.CodeSource java.security.ProtectionDomain.getCodeSource()' on a null object reference
एलन लूस

मैंने उत्तर को संपादित किया और पूरी विधि लिखी जिसका मैंने एक सॉफ्टवेयर में उपयोग किया
gbii

0

कोड का पालन करें!

/ Src / मुख्य / संसाधन / फ़ाइल

streamToFile(getClass().getClassLoader().getResourceAsStream("file"))

public static File streamToFile(InputStream in) {
    if (in == null) {
        return null;
    }

    try {
        File f = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
        f.deleteOnExit();

        FileOutputStream out = new FileOutputStream(f);
        byte[] buffer = new byte[1024];

        int bytesRead;
        while ((bytesRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesRead);
        }

        return f;
    } catch (IOException e) {
        LOGGER.error(e.getMessage(), e);
        return null;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.