জাভাতে একটি ওয়াইল্ডকার্ড স্ট্রিংয়ের সাথে মেলে এমন ফাইলগুলি কীভাবে সন্ধান করবেন?


157

এটি সত্যই সহজ হওয়া উচিত। আমার যদি এর মতো স্ট্রিং থাকে:

../Test?/sample*.txt

তাহলে এই প্যাটার্নের সাথে মেলে এমন ফাইলগুলির একটি তালিকা পাওয়ার জন্য একটি সাধারণভাবে গ্রহণযোগ্য উপায় কী? (যেমন এটি মিলতে হবে ../Test1/sample22b.txtএবং../Test4/sample-spiffy.txt কিন্তু ../Test3/sample2.blahবা ../Test44/sample2.txt)

আমি একবার দেখেছি org.apache.commons.io.filefilter.WildcardFileFilter এবং এটি সঠিক পশুর মতো মনে হচ্ছে তবে আপেক্ষিক ডিরেক্টরি পথে ফাইলগুলি অনুসন্ধানের জন্য কীভাবে এটি ব্যবহার করব তা নিশ্চিত নই।

আমি মনে করি যে আমি পিপীলিকার উত্সটি দেখতে পাচ্ছি কারণ এটি ওয়াইল্ডকার্ড সিনট্যাক্স ব্যবহার করে তবে আমি অবশ্যই এখানে খুব সুন্দর কিছু অনুপস্থিত।

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


2
এটি জাভা নয়, ওয়াইল্ডকার্ডগুলি পার্সিংয়ের শেল। আপনি এগুলি এড়াতে পারেন, তবে সঠিক ফর্ম্যাটটি আপনার সিস্টেমে নির্ভর করে।
মাইকেল ম্যাইইয়ার্স

2
না এইটা না. উইন্ডোজ * ওয়াইল্ডকার্ডগুলি পার্স করে না। আমি এটি একটি ডামি ব্যাচফাইলে একই সিনট্যাক্স চালিয়ে এবং # 1 যা টেস্ট / * ছিল printing এটি "টেস্ট / *। আপত্তি" প্রিন্ট করে। জাভা মনে হচ্ছে এখানে কিছু অদ্ভুত কিছু করেছে।
জেসন এস

হু, আপনি ঠিক বলেছেন; প্রায় সমস্ত বিল্টিন শেল কমান্ডগুলি ওয়াইল্ডকার্ডগুলি প্রসারিত করে তবে শেল নিজেই তা করে না। যাইহোক, আপনি কেবল ওয়াইল্ডকার্ডগুলি পার্স করা থেকে জাভাকে রাখার জন্য উক্তিগুলিতে উদ্ধৃতি দিতে পারেন: জাভা মাই ক্লাস "টেস্ট / * objজেক্ট"
মাইকেল মায়ারস

3
6+ বছর পরে, যারা স্ক্রোলিংকে ঘৃণা করছেন এবং জাভা> = 7 শূন্য-ডিপ সমাধান চান, তাদের জন্য নীচে @ ভ্যাডজিম উত্তরটি দেখুন এবং আপত্তি করুন বা ডকস.ওরাকল.com/javase/tutorial/essential/ io /find.html
এয়ারক্যাম

উত্তর:


81

অ্যাপাচি পিঁপড়া থেকে ডিরেক্টরি স্ক্যানার বিবেচনা করুন:

DirectoryScanner scanner = new DirectoryScanner();
scanner.setIncludes(new String[]{"**/*.java"});
scanner.setBasedir("C:/Temp");
scanner.setCaseSensitive(false);
scanner.scan();
String[] files = scanner.getIncludedFiles();

আপনাকে এন্ট.জার রেফারেন্স করতে হবে (পিপীলিকা 1.7.1 এর জন্য ~ 1.3 এমবি)।


1
চমৎকার! বিটিডাব্লু, স্ক্যানার.জেটআইনক্লুডডাইরেক্টরিজ () আপনার ডিরেক্টরি প্রয়োজন হলে এটি একই কাজ করে। (getIncusedFiles কাজ করবে না)
তিলমান


1
@ মোড়াকি যা পৃথক উত্তর হিসাবে অন্তর্ভুক্ত, কোনও মন্তব্য নয়
জেসন এস

এই ঠিক একই প্লেক্সাস- ইউটিস (241 কেবি) DirectoryScannerপাওয়া যায় । যা তখন ছোট (1.9Mb)। ant.jar
ভারহেন

এইটা কাজ করে. তবে এটি lsএকই ফাইল প্যাটার্নের সাথে তুলনায় অত্যন্ত ধীর বলে মনে হচ্ছে ( ls <pattern>ডাইরেক্টরিস্ক্যানার ব্যবহারের সময় কয়েক মিনিট ব্যবহার করে মিনিসেকেন্ড ) ...
ডকসপ্পার

121

অ্যাপাচি কমন্স-আইও ( এবং পদ্ধতিগুলি) FileUtilsথেকে চেষ্টা করুন :listFilesiterateFiles

File dir = new File(".");
FileFilter fileFilter = new WildcardFileFilter("sample*.java");
File[] files = dir.listFiles(fileFilter);
for (int i = 0; i < files.length; i++) {
   System.out.println(files[i]);
}

TestXফোল্ডারগুলির সাথে আপনার সমস্যা সমাধানের জন্য , আমি প্রথমে ফোল্ডারের তালিকার মাধ্যমে পুনরাবৃত্তি করব:

File[] dirs = new File(".").listFiles(new WildcardFileFilter("Test*.java");
for (int i=0; i<dirs.length; i++) {
   File dir = dirs[i];
   if (dir.isDirectory()) {
       File[] files = dir.listFiles(new WildcardFileFilter("sample*.java"));
   }
}

বেশ 'ব্রুট ফোর্স' সমাধান তবে ভাল কাজ করা উচিত। যদি এটি আপনার প্রয়োজনের সাথে খাপ খায় না, আপনি সর্বদা RegexFileFilter ব্যবহার করতে পারেন ।


2
ঠিক আছে, এখন আপনি জেসন এস যখন প্রশ্ন পোস্ট করেছিলেন তখন ঠিক কোথায় ছিলেন।
মাইকেল ম্যাইইয়ার্স

বেশ না। এছাড়াও ব্যবহার করা যেতে পারে এমন রেজেক্সফিলফিল্টার রয়েছে (তবে ব্যক্তিগতভাবে কখনও এটি করার প্রয়োজন হয়নি)।
ভ্লাদিমির

57

এখানে জাভা 7 নিও গ্লোব্বিং এবং জাভা 8 ল্যাম্বডাস দ্বারা চালিত প্যাটার্ন অনুসারে ফাইলগুলি তালিকা করার উদাহরণ রয়েছে :

    try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(
            Paths.get(".."), "Test?/sample*.txt")) {
        dirStream.forEach(path -> System.out.println(path));
    }

অথবা

    PathMatcher pathMatcher = FileSystems.getDefault()
        .getPathMatcher("regex:Test./sample\\w+\\.txt");
    try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(
            new File("..").toPath(), pathMatcher::matches)) {
        dirStream.forEach(path -> System.out.println(path));
    }

13
বাFiles.walk(Paths.get("..")).filter(matcher::matches).forEach(System.out::println);
অ্যামিবে

@ কাস্টনার_লা, হ্যাঁ, সহায়ক ল্যাম্বডাস এবং পদ্ধতির উল্লেখগুলি ব্যতীত।
ভাদজিম

29

আপনি আপনার ওয়াইল্ডকার্ড স্ট্রিংটিকে একটি নিয়মিত অভিব্যক্তিতে রূপান্তর করতে পারেন এবং স্ট্রিংয়ের matchesপদ্ধতিতে এটি ব্যবহার করতে পারেন । আপনার উদাহরণ অনুসরণ:

String original = "../Test?/sample*.txt";
String regex = original.replace("?", ".?").replace("*", ".*?");

এটি আপনার উদাহরণগুলির জন্য কাজ করে:

Assert.assertTrue("../Test1/sample22b.txt".matches(regex));
Assert.assertTrue("../Test4/sample-spiffy.txt".matches(regex));

এবং পাল্টা উদাহরণ:

Assert.assertTrue(!"../Test3/sample2.blah".matches(regex));
Assert.assertTrue(!"../Test44/sample2.txt".matches(regex));

3
এটি এমন ফাইলে কাজ করবে না যেগুলিতে (, + বা $
ডিজেজেক

আমি 'স্ট্রিংস রেজেক্স = "^" + এস.রেপ্লেস ("?", "।?") ব্যবহার করেছি। প্রতিস্থাপন (" ", "। ?") + "$"' (কিছুটা কারণে আমার মন্তব্যে নক্ষত্রগুলি অদৃশ্য হয়ে গেল। ..)
জৌনি আরো

2
* এর সাথে *। * প্রতিস্থাপন করবেন কেন? ? পাবলিক স্ট্যাটিক বুলিয়ান হ'ল ফাইলম্যাচটারেজফিলপ্যাটার্ন (চূড়ান্ত ফাইল এফ, চূড়ান্ত স্ট্রিং টার্গেটপ্যাটার্ন) {`ring স্ট্রিং রেজেক্স = টার্গেটপ্যাটার্ন.রেপ্লেস ("। "," \\। ");` regex = regex.replace("?", ".?").replace("* ", ".*"); return f.getName().matches(regex); }
টনি

যেহেতু ওপি "ওয়াইল্ডকার্ডযুক্ত সাধারণ পাথ" চেয়েছিল, আপনাকে আরও বিশেষ অক্ষর উদ্ধৃত করতে হবে। আমি বরং প্যাটার্ন.কোয়েটটি ব্যবহার করব:StringBuffer regexBuffer = ...; Matcher matcher = Pattern.compile("(.*?)([*?])").matcher(original); while (matcher.find()) { matcher.appendReplacement(regexBuffer, (Pattern.quote(matcher.group(1)) + (matcher.group(2).equals("*") ? ".*?" : ".?")).replace("\\", "\\\\").replace("$", "\\$")); } matcher.appendTail(regexBuffer);
এন্ডলসস্ক্লাইফ

সংযোজন: "?" একটি বাধ্যতামূলক চরকে বোঝায় তাই এটি .পরিবর্তে পরিবর্তিত করা উচিত .?
এন্ড্লোস শ্লাইফ

23

জাভা 8 যেহেতু আপনি Files#findসরাসরি থেকে পদ্ধতি ব্যবহার করতে পারেন java.nio.file

public static Stream<Path> find(Path start,
                                int maxDepth,
                                BiPredicate<Path, BasicFileAttributes> matcher,
                                FileVisitOption... options)

ব্যবহারের উদাহরণ

Files.find(startingPath,
           Integer.MAX_VALUE,
           (path, basicFileAttributes) -> path.toFile().getName().matches(".*.pom")
);

1
স্ট্রিমে রাখা প্রথম ম্যাচের পথটি মুদ্রণ করার জন্য আপনি উদাহরণটি প্রসারিত করতে পারেন?
jxramos

18

আপনাকে এখনই সহায়তা করতে পারে না, তবে জেডিকে 7 "আরও এনআইও বৈশিষ্ট্যগুলি" এর অংশ হিসাবে গ্লোব এবং রেজেক্স ফাইলের নামের সাথে মিলে যাওয়ার উদ্দেশ্যে।


3
জাভা 7 এ: ফাইলস.নিউইডোরিটোরিস্ট্রিম (পথ, গ্লোব-প্যাটার্ন)
প্যাট নিমিমায়ার

13

ওয়াইল্ডকার্ড লাইব্রেরি দক্ষতার সাথে গ্লোব এবং রেজেক্স ফাইলের মিল দুটি করে:

http://code.google.com/p/wildcard/

বাস্তবায়ন সংক্ষিপ্ত - জেআরটি মাত্র 12.9 কিলোবাইট।


2
একমাত্র অসুবিধাটি হ'ল এটি ম্যাভেন সেন্ট্রালে নেই
ইয়েগোর 256

3
এটি ওএসএস, এগিয়ে গিয়ে ম্যাভেন সেন্ট্রালে রাখুন। :)
NateS

10

কোনও বাহ্যিক আমদানি না করেই সহজ উপায় হ'ল এই পদ্ধতিটি ব্যবহার করা

আমি বিলিং_201208.csv, বিলিং_201209.csv, বিলিং_201210.csv নামের সিএসভি ফাইল তৈরি করেছি এবং এটি দেখতে ঠিক আছে বলে মনে হচ্ছে।

উপরে তালিকাভুক্ত ফাইল উপস্থিত থাকলে আউটপুট নিম্নলিখিত হবে

found billing_201208.csv
found billing_201209.csv
found billing_201210.csv

    // আমদানি ব্যবহার করুন -> java.io.File আমদানি করুন
        পাবলিক স্ট্যাটিক অকার্যকর প্রধান (স্ট্রিং [] আরগস) {
        স্ট্রিং পাথ টোস্ক্যান = "";
        স্ট্রিং টার্গেট_ফাইল; // fileThatYouWantToFilter
        ফাইল ফোল্ডারটিওস্ক্যান = নতুন ফাইল (পাথটোস্ক্যান); 

    File[] listOfFiles = folderToScan.listFiles();

     for (int i = 0; i < listOfFiles.length; i++) {
            if (listOfFiles[i].isFile()) {
                target_file = listOfFiles[i].getName();
                if (target_file.startsWith("billing")
                     && target_file.endsWith(".csv")) {
                //You can add these files to fileList by using "list.add" here
                     System.out.println("found" + " " + target_file); 
                }
           }
     }    
}


6

অন্য উত্তরে পোস্ট করা হিসাবে, ওয়াইল্ডকার্ড লাইব্রেরি গ্লোব এবং রেজেক্স ফাইলের মিল উভয়ের জন্য কাজ করে: http://code.google.com/p/wildcard/

আমি * নিক্স স্টাইল ফাইল সিস্টেমের সাথে নিখুঁত এবং আপেক্ষিক সহ গ্লোব নিদর্শনগুলির সাথে মেলে নীচের কোডটি ব্যবহার করেছি:

String filePattern = String baseDir = "./";
// If absolute path. TODO handle windows absolute path?
if (filePattern.charAt(0) == File.separatorChar) {
    baseDir = File.separator;
    filePattern = filePattern.substring(1);
}
Paths paths = new Paths(baseDir, filePattern);
List files = paths.getFiles();

এটি করার জন্য আমি আপাচি কমন্স আইও লাইব্রেরিতে ফাইল ইউটিলস.লিস্ট ফাইলগুলির পদ্ধতিগুলি পাওয়ার চেষ্টা করার জন্য কিছু সময় ব্যয় করেছি (ভ্লাদিমিরের উত্তর দেখুন) তবে এর কোনও সফলতা হয়নি (আমি এখন বুঝতে পারি / মনে করি এটি কেবল একবারে ডিরেক্টরি বা ফাইলের সাথে মেলে এমন প্যাটার্নটি পরিচালনা করতে পারে) ।

অতিরিক্তভাবে, সালিসী ব্যবহারকারীরা সম্পূর্ণ ফাইল সিস্টেম অনুসন্ধান না করেই সম্পূর্ণ ধরণের গ্লোব নিদর্শন সরবরাহ করে রেগেক্স ফিল্টারগুলি (ফ্যাবিয়ানের উত্তর দেখুন) ব্যবহার করে বৃহত্তম নন-রেজেক্স / গ্লোব উপসর্গ নির্ধারণের জন্য সরবরাহকৃত গ্লোবকে কিছু প্রাক-প্রসেসিং প্রয়োজন হবে।

অবশ্যই, জাভা 7 অনুরোধ করা কার্যকারিতা সুন্দরভাবে পরিচালনা করতে পারে, তবে দুর্ভাগ্যক্রমে আমি আপাতত জাভা 6 এর সাথে আটকে আছি। গ্রন্থাগারটি তুলনামূলকভাবে 13.5kb আকারে বিয়োগ min

পর্যালোচকদের জন্য নোট: আমি এই লাইব্রেরির উল্লেখ করে বিদ্যমান উত্তরের সাথে উপরেরটি যুক্ত করার চেষ্টা করেছি তবে সম্পাদনাটি প্রত্যাখ্যান করা হয়েছিল। আমার কাছে এটিকে মন্তব্য হিসাবে যুক্ত করার মতো পর্যাপ্ত প্রতিনিধি নেই। এর চেয়ে ভাল উপায় কি নেই ...


আপনি কি অন্য কোথাও আপনার প্রকল্পটি স্থানান্তর করার পরিকল্পনা করছেন? কোড. google.com/p/support/wiki/ReadOnlyTransition
লুচ এম

1
'এটি আমার প্রকল্প নয়, এবং দেখে মনে হচ্ছে এটি ইতিমধ্যে স্থানান্তরিত হয়েছে: github.com/EsotericSoftware/wildcard
অলিভার কলম্যান

5

আপনি ব্যবহার করতে সক্ষম হওয়া উচিত WildcardFileFilterSystem.getProperty("user.dir")কাজের ডিরেক্টরি পেতে কেবল ব্যবহার করুন use এটা চেষ্টা কর:

public static void main(String[] args) {
File[] files = (new File(System.getProperty("user.dir"))).listFiles(new WildcardFileFilter(args));
//...
}

আপনার ওয়াইল্ডকার্ড ফিল্টার ব্যবহার অনুমান করে এর *সাথে প্রতিস্থাপনের প্রয়োজন হবে না । আমি এটি পরীক্ষা করেছি না, তবে আমি নিয়মিত প্যাটার্ন এবং ফাইল ফিল্টার ব্যবহার করি।[.*]java.regex.Pattern



3

অ্যাপাচি ফিল্টার একটি পরিচিত ডিরেক্টরিতে ফাইলগুলি পুনরাবৃত্ত করার জন্য নির্মিত। ডিরেক্টরিতে ওয়াইল্ডকার্ডগুলিকে অনুমতি দেওয়ার জন্য আপনাকে ' \' বা ' /' এর পাথটি বিভক্ত করতে হবে এবং প্রতিটি অংশে আলাদাভাবে একটি ফিল্টার করতে হবে do


1
এটি কাজ করে। এটি কিছুটা বিরক্তিকর ছিল, তবে বিশেষত সমস্যায় ভুগছে না। যাইহোক, আমি গ্লোব মিলের জন্য জেডিকে 7 এর বৈশিষ্ট্যগুলির অপেক্ষায় রয়েছি।
জেসন এস

0

ব্যবহার না করে যেমন কিছু করুন:

File myRelativeDir = new File("../../foo");
String fullPath = myRelativeDir.getCanonicalPath();
Sting wildCard = fullPath + File.separator + "*.txt";

// now you have a fully qualified path

তারপরে আপনাকে আপেক্ষিক পাথ সম্পর্কে চিন্তা করতে হবে না এবং প্রয়োজন অনুসারে আপনার ওয়াইল্ডকার্ডিং করতে পারেন।


1
কারণ আপেক্ষিক পথে ওয়াইল্ডকার্ডও থাকতে পারে।
জেসন এস


0

ব্যবহার পদ্ধতি:

public static boolean isFileMatchTargetFilePattern(final File f, final String targetPattern) {
        String regex = targetPattern.replace(".", "\\.");  //escape the dot first
        regex = regex.replace("?", ".?").replace("*", ".*");
        return f.getName().matches(regex);

    }

jUnit পরীক্ষা:

@Test
public void testIsFileMatchTargetFilePattern()  {
    String dir = "D:\\repository\\org\my\\modules\\mobile\\mobile-web\\b1605.0.1";
    String[] regexPatterns = new String[] {"_*.repositories", "*.pom", "*-b1605.0.1*","*-b1605.0.1", "mobile*"};
    File fDir = new File(dir);
    File[] files = fDir.listFiles();

    for (String regexPattern : regexPatterns) {
        System.out.println("match pattern [" + regexPattern + "]:");
        for (File file : files) {
            System.out.println("\t" + file.getName() + " matches:" + FileUtils.isFileMatchTargetFilePattern(file, regexPattern));
        }
    }
}

আউটপুট:

match pattern [_*.repositories]:
    mobile-web-b1605.0.1.pom matches:false
    mobile-web-b1605.0.1.war matches:false
    _remote.repositories matches:true
match pattern [*.pom]:
    mobile-web-b1605.0.1.pom matches:true
    mobile-web-b1605.0.1.war matches:false
    _remote.repositories matches:false
match pattern [*-b1605.0.1*]:
    mobile-web-b1605.0.1.pom matches:true
    mobile-web-b1605.0.1.war matches:true
    _remote.repositories matches:false
match pattern [*-b1605.0.1]:
    mobile-web-b1605.0.1.pom matches:false
    mobile-web-b1605.0.1.war matches:false
    _remote.repositories matches:false
match pattern [mobile*]:
    mobile-web-b1605.0.1.pom matches:true
    mobile-web-b1605.0.1.war matches:true
    _remote.repositories matches:false

আপনি কেবল ফাইল সিস্টেমের পাথ দিয়ে পাঠ্য সন্ধান করতে পারবেন না; অন্যথায় foo/bar.txtমেলে foo?bar.txtএবং এটি সঠিক নয়
জেসন এস

জেসন আমি file.getName () ব্যবহার করেছি যার মধ্যে পথ নেই।
টনি

তাহলে আমি যে উদাহরণ দিয়েছি তা এটি কার্যকর করে না:../Test?/sample*.txt
জেসন এস

0
Path testPath = Paths.get("C:\");

Stream<Path> stream =
                Files.find(testPath, 1,
                        (path, basicFileAttributes) -> {
                            File file = path.toFile();
                            return file.getName().endsWith(".java");
                        });

// Print all files found
stream.forEach(System.out::println);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.