क्या एक क्लासपैथ संसाधन प्राप्त करने के लिए एक एपीआई है (उदाहरण के लिए मुझे क्या मिलेगा Class.getResource(String)
) java.nio.file.Path
? आदर्श रूप से, मैं Path
क्लासपैथ संसाधनों के साथ फैंसी नए एपीआई का उपयोग करना चाहूंगा ।
क्या एक क्लासपैथ संसाधन प्राप्त करने के लिए एक एपीआई है (उदाहरण के लिए मुझे क्या मिलेगा Class.getResource(String)
) java.nio.file.Path
? आदर्श रूप से, मैं Path
क्लासपैथ संसाधनों के साथ फैंसी नए एपीआई का उपयोग करना चाहूंगा ।
जवाबों:
यह एक मेरे लिए काम करता है:
return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());
Thread.currentThread().getContextClassLoader().getResource(resourceName).toURI()
यह मानते हुए कि आप क्या करना चाहते हैं, Classpath से आने वाले संसाधन पर Files.lines (...) को कॉल करें - संभवतः एक जार के भीतर से।
चूंकि ओरेकल ने इस बात की धारणा को पुष्ट किया है कि जब कोई पथ get get not द्वारा एक पथ है। स्रोत एक प्रयोग करने योग्य पथ को वापस करता है यदि यह एक जार फ़ाइल में रहता है, तो आपको ऐसा करने की आवश्यकता है:
Stream<String> stream = new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("/filename.txt"))).lines();
class.getResource
एक स्लैश की आवश्यकता है लेकिन स्लैश के getSystemResourceAsStream
साथ उपसर्ग किए जाने पर फ़ाइल नहीं मिल सकती है।
सबसे सामान्य समाधान इस प्रकार है:
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);
}
});
फिर, यह फिर से सभी संस्करणों और भंडारण विधियों के साथ काम करेगा।
यह पता चला है कि आप ऐसा कर सकते हैं, बिल्ट-इन जिप फाइल सिस्टम प्रोवाइडर की मदद से । हालांकि, 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);
}
अपडेट करें:
यह ठीक से इंगित किया गया है कि उपरोक्त कोड में एक संसाधन रिसाव है, क्योंकि कोड एक नया फाइलसिस्टम ऑब्जेक्ट खोलता है लेकिन इसे कभी बंद नहीं करता है। सबसे अच्छा तरीका यह है कि एक उपभोक्ता-जैसी कार्यकर्ता वस्तु को पारित किया जाए, बहुत पसंद है कि होल्गर इसका उत्तर कैसे देता है। कार्यकर्ता के लिए जो कुछ भी करने की जरूरत है उसे पाथ के साथ करने के लिए जिप्एसएफ फाइलसिस्टम को पर्याप्त समय तक खोलें (जब तक कि कार्यकर्ता बाद में उपयोग के लिए पथ ऑब्जेक्ट को स्टोर करने की कोशिश नहीं करता है), तब फाइलसिस्टम को बंद करें।
newFileSystem
कई संसाधनों को हमेशा के लिए खुले घूम सकता है। यद्यपि @raisercostin परिशिष्ट पहले से बनाई गई फ़ाइल सिस्टम बनाने की कोशिश करते समय त्रुटि से बचता है, यदि आप लौटे का उपयोग करने का प्रयास करते हैं तो आपको Path
एक मिलेगा ClosedFileSystemException
। @ होलगर प्रतिक्रिया मेरे लिए अच्छी तरह से काम करती है।
FileSystem
। यदि आप एक जार से एक संसाधन लोड करते हैं, और फिर आप आवश्यक बनाते हैं FileSystem
- तो FileSystem
आप उसी जार से अन्य संसाधनों को लोड करने की अनुमति भी देंगे। इसके अलावा, एक बार जब आप नया बना FileSystem
लेते हैं, तो आप केवल संसाधन का उपयोग करके फिर से लोड करने का प्रयास कर सकते हैं Paths.get(Path)
और कार्यान्वयन स्वचालित रूप से नए का उपयोग करेगा FileSystem
।
#getPath(String)
पर विधि का उपयोग करने की आवश्यकता नहीं है FileSystem
।
मैंने Paths
आपकी कक्षा के संसाधनों से पढ़ने के लिए एक छोटा सहायक तरीका लिखा है । यह उपयोग करने के लिए काफी आसान है क्योंकि इसमें केवल उस वर्ग के संदर्भ की आवश्यकता है जिसे आपने अपने संसाधनों के साथ-साथ संसाधन के नाम पर संग्रहीत किया है।
public static Path getResourcePath(Class<?> resourceClass, String resourceName) throws URISyntaxException {
URL url = resourceClass.getResource(resourceName);
return Paths.get(url.toURI());
}
आप जार फ़ाइल के अंदर संसाधनों से यूआरआई नहीं बना सकते। आप बस इसे अस्थायी फ़ाइल में लिख सकते हैं और फिर इसका उपयोग कर सकते हैं (java8):
Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);
जावा में 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();
}
आपको 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)) {
....
}
}
Paths.get(URI)
´URL.toURI (), and last
getResource () `है जो एक रिटर्न देता हैURL
। आप उन लोगों को एक साथ श्रृंखला में सक्षम हो सकते हैं। हालांकि हेवन की कोशिश नहीं हुई।