java.nio.file.Path একটি শ্রেণিপথ সংস্থান জন্য


143

একটি ক্লাসপথ সংস্থান (যেমন আমি যা থেকে পেয়েছি Class.getResource(String)) পেতে একটি API আছে java.nio.file.Path? আদর্শভাবে, আমি Pathক্লাসপথ সংস্থান সহ অভিনব নতুন এপিআই ব্যবহার করতে চাই ।


3
ভাল, দীর্ঘ পথ অবলম্বন করা ( Paths.get(URI)পাং উদ্দেশ্যযুক্ত), আপনার পরে ´ URL.toURI () , and last getResource () `যা প্রত্যাবর্তন করে URL। আপনি তাদের একসাথে চেইন করতে সক্ষম হতে পারে। হ্যাভান্ট যদিও চেষ্টা করেছিলেন।
নীলশ ২৯:৩০

উত্তর:


174

এটি আমার জন্য কাজ করে:

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

7
@VGR যদি .jar ফাইলের সংস্থানগুলি এই চেষ্টা করতে পারে `রিসোর্স রিসোর্স = নতুন ক্লাসপাথরেসোর্স (" Use.txt "); BufferedReader পাঠক নতুন BufferedReader (নতুন InputStreamReader (resource.getInputStream ())) = 'দয়া করে দেখুন stackoverflow.com/questions/25869428/...
zhuguowei

8
@ ঝুগুওয়ে এটি একটি বসন্ত-নির্দিষ্ট পদ্ধতির। স্প্রিং ব্যবহৃত হচ্ছে না তখন এটি মোটেও কাজ করে না।
রায়ান জে ম্যাকডনফ

2
যদি আপনার অ্যাপ্লিকেশনটি সিস্টেমের ক্লাসলোডারের উপর নির্ভর করে না, এটি হওয়া উচিতThread.currentThread().getContextClassLoader().getResource(resourceName).toURI()
ThrawnCA

27

অনুমান করে যে আপনি যা করতে চান, তা ক্লাসপথ থেকে আসা একটি সংস্থায় ফাইলগুলি.লাইনস (...) কল করুন - সম্ভবত জারের মধ্যে থেকে।

যেহেতু ওরাকল গিটার রিসোর্সটি কোনও জার ফাইলের মধ্যে থাকে যদি তা ব্যবহারযোগ্য পথটি ফেরত না দেয় তখন কোনও পথ যখন একটি পথ হয় তার ধারণাকে বোঝায়, আপনার যা করা দরকার তা হ'ল এরকম:

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 থেকে জাভা ১০ পর্যন্ত কাজ করে। এটি নতুন একটি খোলার আগে ইতিমধ্যে একটি উন্মুক্ত ফাইল সিস্টেম আছে কিনা তা অনুসন্ধান করে 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);
    }
});

তারপরে, এটি আবার সমস্ত সংস্করণ এবং স্টোরেজ পদ্ধতিতে কাজ করবে।


1
এই সমাধান দুর্দান্ত কাজ করে! আমি নিশ্চিত করতে পারি যে এটি উভয় ডিরেক্টরি ক্লাসপাথ এবং জার শ্রেণিপথগুলিতে সমস্ত সংস্থান (ফাইল, ডিরেক্টরি) নিয়ে কাজ করে। জাভা 7+ এ প্রচুর সংস্থান অনুলিপি করা উচিত এটি অবশ্যই।
মিচেল স্ক্যাগস

10

দেখা যাচ্ছে যে আপনি বিল্ট-ইন জিপ ফাইল সিস্টেম সরবরাহকারীর সহায়তায় এটি করতে পারেন । তবে সরাসরি কোনও উত্স ইউআরআই পাস করা কার্যকর 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);
}

হালনাগাদ:

এটি যথাযথভাবে উল্লেখ করা হয়েছে যে উপরের কোডটিতে একটি রিসোর্স লিক রয়েছে, যেহেতু কোডটি একটি নতুন ফাইলসিস্টেম অবজেক্ট খোলে তবে কখনও এটি বন্ধ করে না। সর্বোত্তম পন্থা হল একজন গ্রাহক-জাতীয় কর্মী বস্তুটি পাস করা, যেমন হোলারের উত্তর এটি কীভাবে করে। জিপএফএএস ফাইলসিস্টেমটি শ্রমিকের পথের জন্য যা কিছু করা দরকার তা করার জন্য যথেষ্ট দীর্ঘ দিন (যতক্ষণ না শ্রমিক পরে ব্যবহারের জন্য পাথ অবজেক্টটি সংরক্ষণ করার চেষ্টা করবেন না), তারপরে ফাইল-সিস্টেমটি বন্ধ করুন।


11
নতুন তৈরি fs সম্পর্কে সাবধানতা অবলম্বন করুন। একই জার ব্যবহার করে দ্বিতীয় কলটি ইতিমধ্যে বিদ্যমান ফাইল সিস্টেম সম্পর্কে অভিযোগ করে একটি ব্যতিক্রম ছুঁড়ে দেবে। (ফাইলসিস্টেম fs = ...) চেষ্টা করা ভাল হবে {fs.getPath (enterName) ফেরান {বা আপনি যদি এই ক্যাশে রাখতে চান তবে আরও উন্নত হ্যান্ডলিং করুন। বর্তমান ফর্মটি ঝুঁকিপূর্ণ।
কিসমেকোস্টিন

3
সম্ভাব্য অ-বন্ধ হওয়া নতুন ফাইল সিস্টেমের ইস্যু ছাড়াও, স্কিম এবং নতুন ফাইল সিস্টেম খোলার প্রয়োজনীয়তার এবং ইউআরআই বিষয়বস্তুগুলির সাথে ঝাঁকুনির মধ্যে সম্পর্কের সম্পর্কে অনুমানগুলি সমাধানের কার্যকারিতা সীমাবদ্ধ করে। আমি একটি নতুন উত্তর সেট আপ করেছি যা একটি সাধারণ পদ্ধতির দেখায় যা অপারেশনকে সহজতর করে এবং একই সাথে নতুন জাভা 9 শ্রেণির স্টোরেজের মতো নতুন স্কিমগুলি পরিচালনা করে। এটি তখনও কাজ করে যখন অ্যাপ্লিকেশনটির মধ্যে অন্য কেউ ইতিমধ্যে ফাইল সিস্টেম খুলেছে (বা পদ্ধতিটিকে একই জারের জন্য দু'বার বলা হয়) ...
হোলগার

এই সমাধানটির ব্যবহারের উপর নির্ভর করে নন-ক্লোজড newFileSystemএকাধিক সংস্থানকে চিরতরে খোলা রাখতে পারে। যদিও ইতিমধ্যে তৈরি ফাইল সিস্টেম তৈরি করার চেষ্টা করার সময় @ রেজারকোস্টিন সংযোজন ত্রুটিটি এড়িয়ে চলেছে, আপনি যদি রিটার্নটি ব্যবহার করার চেষ্টা করেন তবে আপনি 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

আপনি জার ফাইলের অভ্যন্তরীণ সংস্থান থেকে ইউআরআই তৈরি করতে পারবেন না। আপনি কেবল এটি টেম্প ফাইলটিতে লিখতে পারেন এবং তারপরে এটি ব্যবহার করতে পারেন (জাভা 8):

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

1

জাভা 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();
    }

0

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)) {
            ....
        }
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.