একটি ক্লাসপথ সংস্থান (যেমন আমি যা থেকে পেয়েছি Class.getResource(String)
) পেতে একটি API আছে java.nio.file.Path
? আদর্শভাবে, আমি Path
ক্লাসপথ সংস্থান সহ অভিনব নতুন এপিআই ব্যবহার করতে চাই ।
একটি ক্লাসপথ সংস্থান (যেমন আমি যা থেকে পেয়েছি Class.getResource(String)
) পেতে একটি API আছে java.nio.file.Path
? আদর্শভাবে, আমি Path
ক্লাসপথ সংস্থান সহ অভিনব নতুন এপিআই ব্যবহার করতে চাই ।
উত্তর:
এটি আমার জন্য কাজ করে:
return Paths.get(ClassLoader.getSystemResource(resourceName).toURI());
Thread.currentThread().getContextClassLoader().getResource(resourceName).toURI()
অনুমান করে যে আপনি যা করতে চান, তা ক্লাসপথ থেকে আসা একটি সংস্থায় ফাইলগুলি.লাইনস (...) কল করুন - সম্ভবত জারের মধ্যে থেকে।
যেহেতু ওরাকল গিটার রিসোর্সটি কোনও জার ফাইলের মধ্যে থাকে যদি তা ব্যবহারযোগ্য পথটি ফেরত না দেয় তখন কোনও পথ যখন একটি পথ হয় তার ধারণাকে বোঝায়, আপনার যা করা দরকার তা হ'ল এরকম:
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 থেকে জাভা ১০ পর্যন্ত কাজ করে। এটি নতুন একটি খোলার আগে ইতিমধ্যে একটি উন্মুক্ত ফাইল সিস্টেম আছে কিনা তা অনুসন্ধান করে so আপনার আবেদনের অন্য একটি উপাদান ইতিমধ্যে একই জিপ / জার ফাইলের জন্য একটি ফাইল সিস্টেম খুলেছে এমন ক্ষেত্রেও কাজ করে।
এটি উপরে বর্ণিত সমস্ত জাভা সংস্করণগুলিতে ব্যবহার করা যেতে পারে, উদাহরণস্বরূপ প্যাকেজের বিষয়বস্তু তালিকাভুক্তকরণে ( 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 inconsistently পথ ফেরৎ /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
হবে না; পরিবর্তে, প্রথমে প্রবেশের নাম ছাড়া জার ইউআরআইয়ের জন্য প্রথমে একটি জিপ ফাইল সিস্টেম তৈরি করতে হবে, তারপরে সেই ফাইল সিস্টেমে প্রবেশের বিষয়টি উল্লেখ করুন:
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
একাধিক সংস্থানকে চিরতরে খোলা রাখতে পারে। যদিও ইতিমধ্যে তৈরি ফাইল সিস্টেম তৈরি করার চেষ্টা করার সময় @ রেজারকোস্টিন সংযোজন ত্রুটিটি এড়িয়ে চলেছে, আপনি যদি রিটার্নটি ব্যবহার করার চেষ্টা করেন তবে আপনি 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());
}
আপনি জার ফাইলের অভ্যন্তরীণ সংস্থান থেকে ইউআরআই তৈরি করতে পারবেন না। আপনি কেবল এটি টেম্প ফাইলটিতে লিখতে পারেন এবং তারপরে এটি ব্যবহার করতে পারেন (জাভা 8):
Path path = File.createTempFile("some", "address").toPath();
Files.copy(ClassLoader.getSystemResourceAsStream("/path/to/resource"), path, StandardCopyOption.REPLACE_EXISTING);
জাভা 8 এ এনআইও ব্যবহার করে রিসোর্স ফোল্ডার থেকে একটি ফাইল পড়ুন
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();
}
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
। আপনি তাদের একসাথে চেইন করতে সক্ষম হতে পারে। হ্যাভান্ট যদিও চেষ্টা করেছিলেন।