java.nio.file.Path एक classpath संसाधन के लिए


143

क्या एक क्लासपैथ संसाधन प्राप्त करने के लिए एक एपीआई है (उदाहरण के लिए मुझे क्या मिलेगा Class.getResource(String)) java.nio.file.Path? आदर्श रूप से, मैं Pathक्लासपैथ संसाधनों के साथ फैंसी नए एपीआई का उपयोग करना चाहूंगा ।


3
ठीक है, लंबे रास्ते (आप का इरादा) को लेते हुए, आपके पास Paths.get(URI)´URL.toURI () , and last getResource () `है जो एक रिटर्न देता है URL। आप उन लोगों को एक साथ श्रृंखला में सक्षम हो सकते हैं। हालांकि हेवन की कोशिश नहीं हुई।
NilsH

जवाबों:


175

यह एक मेरे लिए काम करता है:

return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());

7
@VGR अगर संसाधन .jar फ़ाइल में यह `संसाधन संसाधन = नया ClassPathResource (" यूज़.टेक्स्ट ") आज़मा सकता है; बफ़रडर रीडर = नया बफ़रडर (नया
इनपुटस्ट्रीमरएडर

8
@zhuguowei जो कि वसंत-विशिष्ट दृष्टिकोण है। जब स्प्रिंग का उपयोग नहीं किया जा रहा है तो यह बिल्कुल भी काम नहीं करता है।
रयान जे। मैकडोनो

2
यदि आपका एप्लिकेशन सिस्टम Thread.currentThread().getContextClassLoader().getResource(resourceName).toURI()
क्लास लोडर

27

यह मानते हुए कि आप क्या करना चाहते हैं, Classpath से आने वाले संसाधन पर Files.lines (...) को कॉल करें - संभवतः एक जार के भीतर से।

चूंकि ओरेकल ने इस बात की धारणा को पुष्ट किया है कि जब कोई पथ get get not द्वारा एक पथ है। स्रोत एक प्रयोग करने योग्य पथ को वापस करता है यदि यह एक जार फ़ाइल में रहता है, तो आपको ऐसा करने की आवश्यकता है:

Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();

1
क्या आपके मामले में पूर्ववर्ती "/" की आवश्यकता है जो मुझे नहीं पता, लेकिन मेरे मामले में class.getResourceएक स्लैश की आवश्यकता है लेकिन स्लैश के getSystemResourceAsStreamसाथ उपसर्ग किए जाने पर फ़ाइल नहीं मिल सकती है।
एडम

11

सबसे सामान्य समाधान इस प्रकार है:

interface IOConsumer<T> {
    void accept(T t) throws IOException;
}
public static void processRessource(URI uri, IOConsumer<Path> action) throws IOException {
    try {
        Path p=Paths.get(uri);
        action.accept(p);
    }
    catch(FileSystemNotFoundException ex) {
        try(FileSystem fs = FileSystems.newFileSystem(
                uri, Collections.<String,Object>emptyMap())) {
            Path p = fs.provider().getPath(uri);
            action.accept(p);
        }
    }
}

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

इसलिए, ऊपर दिए गए समाधान में वास्तविक कार्रवाई को समझाया जाता है interface, दोनों मामलों को संभालता है, सुरक्षित रूप से दूसरे मामले में बाद में बंद होता है, और जावा 7 से जावा 10. पर काम करता है। यह जांच करता है कि क्या नया खोलने से पहले ही एक खुली फाइल सिस्टम है, इसलिए यह इस मामले में भी काम करता है कि आपके आवेदन के एक अन्य घटक ने पहले ही समान जिप / जार फ़ाइल के लिए एक फाइल सिस्टम खोला है।

इसका उपयोग उपरोक्त सभी जावा संस्करणों में किया जा सकता है, जैसे कि पैकेज की सामग्री ( java.langउदाहरण में) को Pathएस के रूप में सूचीबद्ध करने के लिए , जैसे:

processRessource(Object.class.getResource("Object.class").toURI(), new IOConsumer<Path>() {
    public void accept(Path path) throws IOException {
        try(DirectoryStream<Path> ds = Files.newDirectoryStream(path.getParent())) {
            for(Path p: ds)
                System.out.println(p);
        }
    }
});

जावा 8 या नए के साथ, आप वास्तविक कार्रवाई का प्रतिनिधित्व करने के लिए लंबोदर भाव या विधि संदर्भ का उपयोग कर सकते हैं, जैसे

processRessource(Object.class.getResource("Object.class").toURI(), path -> {
    try(Stream<Path> stream = Files.list(path.getParent())) {
        stream.forEach(System.out::println);
    }
});

वही करने के लिए।


जावा 9 के मॉड्यूल सिस्टम की अंतिम रिलीज ने उपरोक्त कोड उदाहरण को तोड़ दिया है। JRE असंगत तरीके से उस मार्ग /java.base/java/lang/Object.classको लौटाता है Object.class.getResource("Object.class")जबकि इसे होना चाहिए /modules/java.base/java/lang/Object.class/modules/जब मूल पथ को न के बराबर बताया जाता है, तो यह अनुपस्थित होने के बाद तय किया जा सकता है :

processRessource(Object.class.getResource("Object.class").toURI(), path -> {
    Path p = path.getParent();
    if(!Files.exists(p))
        p = p.resolve("/modules").resolve(p.getRoot().relativize(p));
    try(Stream<Path> stream = Files.list(p)) {
        stream.forEach(System.out::println);
    }
});

फिर, यह फिर से सभी संस्करणों और भंडारण विधियों के साथ काम करेगा।


1
यह समाधान महान काम करता है! मैं यह पुष्टि कर सकता हूं कि यह सभी संसाधनों (फाइल, निर्देशिका) के साथ काम करता है दोनों डायरेक्टरी क्लासपैथ और जार क्लासपैथ में। यह निश्चित रूप से है कि जावा 7+ में बहुत सारे संसाधनों की नकल कैसे की जानी चाहिए।
मिशेल स्कैग्स

10

यह पता चला है कि आप ऐसा कर सकते हैं, बिल्ट-इन जिप फाइल सिस्टम प्रोवाइडर की मदद से । हालांकि, Paths.getकाम करने के लिए सीधे संसाधन URI पास करना; इसके बजाय, पहले किसी को प्रवेश नाम के बिना जार यूआरआई के लिए एक ज़िप फाइल सिस्टम बनाना होगा, फिर उस फाइल सिस्टम में प्रविष्टि का संदर्भ लें:

static Path resourceToPath(URL resource)
throws IOException,
       URISyntaxException {

    Objects.requireNonNull(resource, "Resource URL cannot be null");
    URI uri = resource.toURI();

    String scheme = uri.getScheme();
    if (scheme.equals("file")) {
        return Paths.get(uri);
    }

    if (!scheme.equals("jar")) {
        throw new IllegalArgumentException("Cannot convert to Path: " + uri);
    }

    String s = uri.toString();
    int separator = s.indexOf("!/");
    String entryName = s.substring(separator + 2);
    URI fileURI = URI.create(s.substring(0, separator));

    FileSystem fs = FileSystems.newFileSystem(fileURI,
        Collections.<String, Object>emptyMap());
    return fs.getPath(entryName);
}

अपडेट करें:

यह ठीक से इंगित किया गया है कि उपरोक्त कोड में एक संसाधन रिसाव है, क्योंकि कोड एक नया फाइलसिस्टम ऑब्जेक्ट खोलता है लेकिन इसे कभी बंद नहीं करता है। सबसे अच्छा तरीका यह है कि एक उपभोक्ता-जैसी कार्यकर्ता वस्तु को पारित किया जाए, बहुत पसंद है कि होल्गर इसका उत्तर कैसे देता है। कार्यकर्ता के लिए जो कुछ भी करने की जरूरत है उसे पाथ के साथ करने के लिए जिप्एसएफ फाइलसिस्टम को पर्याप्त समय तक खोलें (जब तक कि कार्यकर्ता बाद में उपयोग के लिए पथ ऑब्जेक्ट को स्टोर करने की कोशिश नहीं करता है), तब फाइलसिस्टम को बंद करें।


11
नए बनाए गए fs से सावधान रहें। उसी जार का उपयोग करने वाला दूसरा कॉल पहले से मौजूद फाइल सिस्टम के बारे में शिकायत करने वाले अपवाद को फेंक देगा। कोशिश करना बेहतर होगा (फाइलसिस्टम एफएस = ...) {रिटर्न एफजेटपैथ (एंट्रीनाम);} या यदि आप चाहते हैं कि यह कैश्ड अधिक उन्नत हैंडलिंग करना है। वर्तमान रूप में जोखिम भरा है।
किशोरीकोस्टिन

3
संभावित रूप से गैर-बंद नई फाइलसिस्टम के मुद्दे के अलावा, योजनाओं के बीच संबंधों के बारे में धारणाएं और एक नई फाइलसिस्टम खोलने की आवश्यकता और यूआरआई सामग्री के साथ गूंज समाधान की उपयोगिता को सीमित करता है। मैंने एक नया उत्तर निर्धारित किया है जो एक सामान्य दृष्टिकोण दिखाता है जो ऑपरेशन को सरल बनाता है और एक ही समय में नए जावा 9 क्लास स्टोरेज जैसी नई योजनाओं को संभालता है। यह तब भी काम करता है जब अनुप्रयोग के भीतर किसी और व्यक्ति ने पहले से ही फाइलसिस्टम खोला है (या विधि को एक ही जार के लिए दो बार कहा जाता है) ...
होल्गर

इस समाधान के उपयोग के आधार पर, गैर बंद newFileSystemकई संसाधनों को हमेशा के लिए खुले घूम सकता है। यद्यपि @raisercostin परिशिष्ट पहले से बनाई गई फ़ाइल सिस्टम बनाने की कोशिश करते समय त्रुटि से बचता है, यदि आप लौटे का उपयोग करने का प्रयास करते हैं तो आपको Pathएक मिलेगा ClosedFileSystemException। @ होलगर प्रतिक्रिया मेरे लिए अच्छी तरह से काम करती है।
जोस एंडियास

मैं बंद नहीं होता FileSystem। यदि आप एक जार से एक संसाधन लोड करते हैं, और फिर आप आवश्यक बनाते हैं FileSystem- तो FileSystemआप उसी जार से अन्य संसाधनों को लोड करने की अनुमति भी देंगे। इसके अलावा, एक बार जब आप नया बना FileSystemलेते हैं, तो आप केवल संसाधन का उपयोग करके फिर से लोड करने का प्रयास कर सकते हैं Paths.get(Path)और कार्यान्वयन स्वचालित रूप से नए का उपयोग करेगा FileSystem
एनएस डू टिट

यानी आपको ऑब्जेक्ट #getPath(String)पर विधि का उपयोग करने की आवश्यकता नहीं है FileSystem
एनएस डू टिट

5

मैंने Pathsआपकी कक्षा के संसाधनों से पढ़ने के लिए एक छोटा सहायक तरीका लिखा है । यह उपयोग करने के लिए काफी आसान है क्योंकि इसमें केवल उस वर्ग के संदर्भ की आवश्यकता है जिसे आपने अपने संसाधनों के साथ-साथ संसाधन के नाम पर संग्रहीत किया है।

public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
    URL url = resourceClass.getResource(resourceName);
    return Paths.get(url.toURI());
}  

1

आप जार फ़ाइल के अंदर संसाधनों से यूआरआई नहीं बना सकते। आप बस इसे अस्थायी फ़ाइल में लिख सकते हैं और फिर इसका उपयोग कर सकते हैं (java8):

Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);

1

जावा में NIO का उपयोग कर संसाधन फ़ोल्डर से एक फ़ाइल पढ़ें

public static String read(String fileName) {

        Path path;
        StringBuilder data = new StringBuilder();
        Stream<String> lines = null;
        try {
            path = Paths.get(Thread.currentThread().getContextClassLoader().getResource(fileName).toURI());
            lines = Files.lines(path);
        } catch (URISyntaxException | IOException e) {
            logger.error("Error in reading propertied file " + e);
            throw new RuntimeException(e);
        }

        lines.forEach(line -> data.append(line));
        lines.close();
        return data.toString();
    }

0

आपको jd फ़ाइल से संसाधन पढ़ने के लिए फाइलसिस्टम को परिभाषित करने की आवश्यकता है जैसा कि https://docs.oracle.com/javase/8/docs/technotes/guides/io/fsp/zipfilesystemprovider.html में बताया गया है । मैं नीचे दिए गए कोड के साथ जार फ़ाइल से संसाधन पढ़ने में सफल रहा:

Map<String, Object> env = new HashMap<>();
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {

        Path path = fs.getPath("/path/myResource");

        try (Stream<String> lines = Files.lines(path)) {
            ....
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.