जावा में वाइल्डकार्ड स्ट्रिंग से मेल खाने वाली फाइलें कैसे खोजें?


157

यह वास्तव में सरल होना चाहिए। अगर मैं इस तरह एक स्ट्रिंग है:

../Test?/sample*.txt

फिर इस पैटर्न से मेल खाने वाली फ़ाइलों की सूची प्राप्त करने का एक आम तौर पर स्वीकृत तरीका क्या है? (उदाहरण के लिए यह मेल खाना चाहिए ../Test1/sample22b.txtऔर ../Test4/sample-spiffy.txtनहीं ../Test3/sample2.blahभी ../Test44/sample2.txt)

मैंने देख लिया है org.apache.commons.io.filefilter.WildcardFileFilterऔर यह सही जानवर की तरह लगता है, लेकिन मुझे यकीन नहीं है कि किसी रिश्तेदार निर्देशिका पथ में फ़ाइलों को खोजने के लिए इसका उपयोग कैसे करें।

मुझे लगता है कि मैं चींटी के लिए स्रोत देख सकता हूं क्योंकि यह वाइल्डकार्ड सिंटैक्स का उपयोग करता है, लेकिन मुझे यहां कुछ स्पष्ट याद आ रहा है।

( संपादित करें : उपरोक्त उदाहरण सिर्फ एक नमूना मामला था। मैं रनवे पर वाइल्डकार्ड वाले सामान्य रास्तों को पार्स करने के लिए रास्ता ढूंढ रहा हूं। मुझे लगा कि यह मिमीयर्स के सुझाव के आधार पर कैसे किया जाए लेकिन यह एक तरह से कष्टप्रद है। इसका उल्लेख नहीं है। जावा जेआरई एक एकल तर्क से मुझे समय और परेशानी को "बचाने" के लिए मुख्य (स्ट्रिंग [] तर्कों) में ऑटो वाइल्डकार्डों को पार्स करने लगता है ... मुझे खुशी है कि मुझे गैर-फ़ाइल तर्क नहीं मिले। मिश्रण।)


2
यह जावा को नहीं बल्कि वाइल्डकार्ड को खोल देने वाला खोल है। आप उनसे बच सकते हैं, लेकिन सटीक प्रारूप आपके सिस्टम पर निर्भर करता है।
माइकल मायर्स

2
नहीं यह नहीं। विंडोज * वाइल्डकार्ड पार्स नहीं करता है। मैंने एक डमी बैचफाइल पर एक ही सिंटैक्स चलाकर और # 1 टेस्ट / * प्रिंट आउट तर्क जो कि .obj फ़ाइलों से भरा एक निर्देशिका की ओर इशारा करते हैं। यह "टेस्ट / *। Obj" को प्रिंट करता है। जावा यहाँ कुछ अजीब करने के लिए लगता है।
जेसन एस

हुह, तुम सही हो; लगभग सभी बिलियन शेल कमांड वाइल्डकार्ड का विस्तार करते हैं, लेकिन शेल स्वयं नहीं करता है। वैसे भी, तुम सिर्फ उद्धरण में तर्क रखा पार्स करने के लिए वाइल्डकार्ड से जावा रखने के लिए कर सकते हैं: जावा MyClass "। टेस्ट / * obj"
माइकल मायर्स

3
6+ साल बाद, उन लोगों के लिए जो स्क्रॉल करना चाहते हैं और Java> = 7 जीरो- डीप सॉल्यूशन चाहते हैं, नीचे देखें और @Vadzim, या वर्चुअली pore / bore by docs.oracle.com/jonase/tutorial/essential/io पर नीचे दिए गए उत्तर को देखें और बढ़ाएं। /find.html
इयरकैम

जवाबों:


81

Apache Ant से DirectoryScanner पर विचार करें:

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

आपको ant.jar (~ 1.7 एमबी चींटी 1.7.1 के लिए) को संदर्भित करना होगा।


1
अति उत्कृष्ट! यदि आपको निर्देशिकाओं की आवश्यकता है तो btw, scanner.getIncludedDirectories () वही करता है। (getIncludedFiles काम नहीं करेगा)
टिल्मैन हाशेर


1
@ मोरकी जो एक अलग उत्तर के रूप में है, टिप्पणी नहीं
जेसन एस

यह ठीक वैसा ही plexus-utils (241Kb) DirectoryScannerमें पाया जाता है । जो तब छोटा होता है (1.9Mb)। ant.jar
वेरगन

यह काम। लेकिन यह lsसमान फ़ाइल पैटर्न ( ls <pattern>डायरेक्टरीसेंसर का उपयोग करते समय बनाम मिनट का उपयोग करके मिलीसेकंड ) की तुलना में बेहद धीमा प्रतीत होता है ...
dokaspar

121

Apache commons-io ( और विधियाँ) 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
ठीक है, अब आप ठीक उसी जगह पर पहुंच गए हैं जहां जेसन एस था जब उसने प्रश्न पोस्ट किया था।
माइकल मायर्स

काफी नहीं। RegexFileFilter का उपयोग किया जा सकता है (लेकिन व्यक्तिगत रूप से ऐसा करने की आवश्यकता कभी नहीं थी)।
व्लादिमीर

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);
amoebe

@Qstnr_La, हाँ, ऑइकलर लैम्ब्डा और विधि संदर्भों को छोड़कर।
वडज़िम

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
यह उन फ़ाइलों के लिए काम नहीं करेगा जिनमें विशेष regex अक्षर हैं (जैसे, + या $
djjeck

मैंने 'स्ट्रिंग regex = "^" + s.replace ("?", "?" का उपयोग किया। प्रतिस्थापित करें (" ", "; ") + "$" (किसी कारण के लिए मेरी टिप्पणी में तारांकन गायब हो गया। ..)
जौनी अरो

2
क्यों * * के साथ प्रतिस्थापित करें? * ? सार्वजनिक स्थिर बूलियन हैफाइलमैचटार्गेटफिलटेनटर्न (अंतिम फाइल एफ, अंतिम स्ट्रिंग टार्गेट स्टेटर्न) {`` स्ट्रिंग regex = targetPattern.replace ("।", "\\"।); ` *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);
EndlosSchleife

परिशिष्ट: "" एक अनिवार्य चार को दर्शाता है, इसलिए इसे .इसके बजाय बदल दिया जाना चाहिए .?
१०:०१

23

Java 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
क्या आप स्ट्रीम में रखे गए पहले मैच का रास्ता प्रिंट करने के लिए उदाहरण का विस्तार कर सकते हैं?
19

18

अभी आपको मदद नहीं मिल सकती है, लेकिन JDK 7 का उद्देश्य ग्लोब और रेगेक्स फ़ाइल नाम "मोर एनआईओ फीचर्स" के हिस्से के रूप में मेल खाना है।


3
जावा 7 में: Files.newDirectoryStream (पथ, ग्लोब-पैटर्न)
Pat Niemeyer

13

वाइल्डकार्ड लाइब्रेरी कुशलतापूर्वक ग्लोब और रेगेक्स फाइलनेम दोनों का मिलान करती है:

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

कार्यान्वयन सफल है - JAR केवल 12.9 किलोबाइट है।


2
एकमात्र नुकसान यह है कि यह मावेन सेंट्रल में नहीं है
yegor256

3
यह ओएसएस है, आगे बढ़ो और इसे मावेन सेंट्रल पर रखो। :)
नैट्स

10

किसी भी बाहरी आयात का उपयोग किए बिना सरल तरीका इस पद्धति का उपयोग करना है

मैंने बिलिंग_201208.csv, बिलिंग_201209.csv, बिलिंग_201210.csv नाम की सीएसवी फाइलें बनाईं और यह ठीक काम करने जैसा लग रहा है।

यदि निम्न सूचीबद्ध फ़ाइलें मौजूद हैं, तो आउटपुट निम्न होगा

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

    // इम्पोर्ट -> इम्पोर्ट java.io.File
        सार्वजनिक स्थैतिक शून्य main (String [] args) {
        स्ट्रिंग pathToScan = "।";
        स्ट्रिंग target_file; // fileThatYouWantToFilter
        फ़ाइल folderToScan = नई फ़ाइल (pathToScan); 

    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/ildcard/

मैंने * निक्स स्टाइल फाइल सिस्टम पर पूर्ण और सापेक्ष सहित ग्लोब पैटर्न से मेल खाने के लिए निम्न कोड का उपयोग किया:

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();

मैंने कुछ समय बिताने के लिए अपाचे कॉमन्स io लाइब्रेरी में FileUtils.listFiles विधियों को प्राप्त करने की कोशिश की (देखें व्लादिमीर का जवाब) ऐसा करने के लिए, लेकिन कोई सफलता नहीं थी (मुझे अब पता चलता है / लगता है कि यह केवल एक समय में एक निर्देशिका या फ़ाइल से मेल खाते पैटर्न को संभाल सकता है) ।

इसके अतिरिक्त, पूरी फाइल सिस्टम को खोजे बिना निरपेक्ष प्रकार के ग्लोब पैटर्न की आपूर्ति करने वाले उपयोगकर्ता के लिए मनमाने ढंग से आपूर्ति किए गए प्रसंस्करण के लिए रेगेक्स फिल्टर (फैबियन का उत्तर देखें) का उपयोग सबसे बड़ा गैर-रेगेक्स / ग्लोब उपसर्ग निर्धारित करने के लिए आपूर्ति किए गए ग्लोब के कुछ प्रीप्रोसेसिंग की आवश्यकता होगी।

बेशक, जावा 7 अनुरोधित कार्यक्षमता को अच्छी तरह से संभाल सकता है, लेकिन दुर्भाग्य से मैं अभी के लिए जावा 6 के साथ फंस गया हूं। पुस्तकालय आकार में 13.5kb पर अपेक्षाकृत छोटा है।

समीक्षकों को ध्यान दें: मैंने इस लाइब्रेरी का उल्लेख करते हुए मौजूदा उत्तर में उपरोक्त को जोड़ने का प्रयास किया लेकिन संपादन अस्वीकार कर दिया गया। मेरे पास इसे टिप्पणी के रूप में जोड़ने के लिए पर्याप्त प्रतिनिधि नहीं है। वहाँ एक बेहतर तरीका नहीं है ...


क्या आप अपने प्रोजेक्ट को कहीं और स्थानांतरित करने की योजना बना रहे हैं? कोड देखें। www.pp /support/wiki/ReadOnlyTransition
Luc M

1
'मेरी परियोजना नहीं है, और ऐसा लगता है कि यह पहले से ही माइग्रेट हो गया है: github.com/EsotericSoftware/wildcard
ओलिवर कोलमैन

5

आप का उपयोग करने में सक्षम होना चाहिए WildcardFileFilter। बस System.getProperty("user.dir")काम कर निर्देशिका प्राप्त करने के लिए उपयोग करें। इसे इस्तेमाल करे:

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

आपको वाइल्डकार्ड फ़िल्टर उपयोगों को संभालने के *साथ बदलने की आवश्यकता नहीं होनी चाहिए । मैंने इसका परीक्षण नहीं किया है, लेकिन मैं लगातार पैटर्न और फ़ाइल फ़िल्टर का उपयोग करता हूं।[.*]java.regex.Pattern



3

अपाचे फ़िल्टर एक ज्ञात निर्देशिका में फ़ाइलों को पुनरावृत्त करने के लिए बनाया गया है। निर्देशिका में वाइल्डकार्ड को भी अनुमति देने के लिए, आपको ' \' या ' /' पर पथ को विभाजित करना होगा और प्रत्येक भाग पर एक फ़िल्टर अलग से करना होगा।


1
यह काम किया। यह थोड़ा कष्टप्रद था, लेकिन विशेष रूप से परेशान करने वाला नहीं था। हालांकि, मैं JDK7 के फीचर्स के लिए ग्लोब मैचिंग का इंतजार कर रहा हूं।
जेसन एस

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);

    }

जॉनीट टेस्ट:

@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और यह सही नहीं है
जेसन एस

जेसन I ने 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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.