2009-09-03 18 views
7

यहाँ मेरा लक्ष्य है। मैं एक मूल निर्देशिका और फ़ाइल नाम को उस विधि में पास करने में सक्षम होना चाहता हूं जो निर्देशिका में उस विशिष्ट फ़ाइल और किसी उप-निर्देशिका में खोज करता है। नीचे वह कोड है जिसके साथ मैं काम कर रहा हूं लेकिन यह वही करने के लिए नहीं कर सकता जो मैं चाहता हूं। यह फ़ाइल जो मैं निर्दिष्ट करता हूं उसे पाउंगा लेकिन कुछ भी वापस नहीं करेगा।खोजें

private static File findFile(File dir, String name) { 
    String file  = ""; 
    File[] dirlist = dir.listFiles(); 

    search: 
     for(int i = 0; i < dirlist.length; i++) { 
      if(dirlist[i].isDirectory()) { 
       findFile(dirlist[i], name); 
      } else if(dirlist[i].getName().matches(name)) { 
       file = dirlist[i].toString(); 
       break search; 
      } 
     } 

    return new File(file); 
} 

मुझे पता है कि यह फ़ाइल चर रहा है जो जहां मैंने पाया फ़ाइल भंडारण कर रहा हूँ रीसेट करता है जब विधि एक निर्देशिका पाता है और अपने आप में कहता है। इसलिए मुझे खाली वापसी मिल रही है। मुझे यकीन नहीं है कि इस लक्ष्य को कैसे पूरा किया जाए या यदि यह भी संभव हो।

+0

इसके अलावा: आप यहां "ब्रेक लेबल" के बजाय नियमित "ब्रेक" का उपयोग/उपयोग कर सकते हैं। (एक सादा वापसी अभी भी @ chssPly76 अंक के रूप में बेहतर है।) –

उत्तर

5

समस्या यह है कि आप पुनरावर्ती कॉल से कुछ भी नहीं लौटा रही हैं है:

if(dirlist[i].isDirectory()) { 
    findFile(dirlist[i], name); // <-- here 
} else if(dirlist[i].getName().matches(name)) { 

मैं निम्नलिखित करना होगा:

private static File findFile(File dir, String name) { 
    File result = null; // no need to store result as String, you're returning File anyway 
    File[] dirlist = dir.listFiles(); 

    for(int i = 0; i < dirlist.length; i++) { 
    if(dirlist[i].isDirectory()) { 
     result = findFile(dirlist[i], name); 
     if (result!=null) break; // recursive call found the file; terminate the loop 
    } else if(dirlist[i].getName().matches(name)) { 
     return dirlist[i]; // found the file; return it 
    } 
    } 
    return result; // will return null if we didn't find anything 
} 
+0

यह काम नहीं करता है अगर फ़ाइल निर्देशिका में मौजूद नहीं है और यह अपवाद उठाएगी – Erfan

1

वास्तव में काम करने के लिए कई समाधान कर रहे हैं। मुझे लगता है कि आप एक अनन्य फ़ाइल (या पहले एक) को फ़ाइल नाम से मेल खाने वाली निर्देशिका वृक्ष में पाई जानी चाहिए। यह अनुकूलन की समस्या है क्योंकि समाधानों का पता लगाने के कई तरीके हैं, और हम एक स्वीकार्य समाधान खोजना चाहते हैं।

1- समाधान का उपयोग कर FileUtils.listFiles

public static File searchFileWithFileUtils(final File file, final String fileName) { 
    File target = null; 
    if(file.isDirectory()) { 
     Collection<File> files = FileUtils.listFiles(file, null, true); 
     for (File currFile : files) { 
      if (currFile.isFile() && currFile.getName().equals(fileName)) { 
       target = currFile; 
       break; 
      } 
     } 
    } 
    return target; 
} 

समाधान पुस्तकालय FileUtils का उपयोग कर, क्योंकि विधि एक उपयुक्त समाधान नहीं है FileUtils#listFiles() भार सभी निर्देशिका/फ़ोल्डर ट्री (लागत महंगी है!)। हम सब पेड़ पता करने के लिए, हम एक बेहतर एल्गोरिथ्म जो जब फ़ाइल पाया जाता है बंद हो जाता है चुन सकते हैं की जरूरत नहीं है।

2- रिकर्सिव समाधान

public static File searchFileRecursive(final File file, final String search) { 
    if (file.isDirectory()) { 
     File[] files = file.listFiles(); 
     for (File f : files) { 
      File target = searchFileRecursive(f, search); 
      if(target != null) { 
       return target; 
      } 
     } 
    } else { 
     if (search.equals(file.getName())) { 
      return file; 
     } 
    } 
    return null; 
} 

एल्गोरिथ्म परीक्षण करता है, तो फ़ाइल किसी भी फ़ोल्डर के अंदर मौजूद है। यदि नहीं, तो यह वर्तमान फ़ोल्डर के सबफ़ोल्डर की कोशिश करता है ... पुनरावर्ती। अगर फ़ाइल वर्तमान शाखा में नहीं मिली है तो यह एक और उपफोल्डर की कोशिश करता है।

अन्वेषण गहरी है, और 1 के एक गहराई में किसी भी फ़ाइल के लिए एल्गोरिथ्म (पिछले शाखाओं पूरी तरह से प्रकट होते हैं!) पिछले सबफ़ोल्डर के पूरी तरह से जानेंगे। इस एल्गोरिदम में पहली शाखा के अंदर गहरे स्थान में फ़ाइलों के लिए सबसे अच्छा प्रदर्शन है।

मामलों के बहुमत में, फ़ाइल स्थान गहरी नहीं है, तो एक और एल्गोरिथ्म है कि अधिकांश मामलों में काम करता है की खोज करें।

3- सबसे तेजी से समाधान: अन्वेषण गहराई

public static File searchFileByDeepness(final String directoryName, final String fileName) { 
    File target = null; 
    if(directoryName != null && fileName != null) { 
     File directory = new File(directoryName); 
     if(directory.isDirectory()) { 
      File file = new File(directoryName, fileName); 
      if(file.isFile()) { 
       target = file; 
      } 
      else { 
       List<File> subDirectories = getSubDirectories(directory); 
       do { 
        List<File> subSubDirectories = new ArrayList<File>(); 
        for(File subDirectory : subDirectories) { 
         File fileInSubDirectory = new File(subDirectory, fileName); 
         if(fileInSubDirectory.isFile()) { 
          return fileInSubDirectory; 
         } 
         subSubDirectories.addAll(getSubDirectories(subDirectory)); 
        } 
        subDirectories = subSubDirectories; 
       } while(subDirectories != null && ! subDirectories.isEmpty()); 
      } 
     } 
    } 
    return target; 
} 

private static List<File> getSubDirectories(final File directory) { 
    File[] subDirectories = directory.listFiles(new FilenameFilter() { 
     @Override 
     public boolean accept(final File current, final String name) { 
      return new File(current, name).isDirectory(); 
     } 
    }); 
    return Arrays.asList(subDirectories); 
} 

प्रत्येक गहराई के लिए से, एल्गोरिथ्म एक ही स्तर के सभी फ़ोल्डर के अंदर फ़ाइल खोज करता है। अगर फ़ाइल नहीं मिली है, तो यह अगले स्तर (गहराई ++) की कोशिश करता है। समांतर अन्वेषण (समरूपता) के कारण, यह समाधान ज्यादातर मामलों में उपयुक्त है।

तुलना:

public class FileLocationFinder { 

    public static void main(final String[] args) { 
     String rootFolder = args[0]; 
     String fileName = args[1]; 

     long start = System.currentTimeMillis(); 
     File target = searchFileWithFileUtils(new File(rootFolder), fileName); 
     System.out.println(target.getAbsolutePath()); 
     System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms"); 

     start = System.currentTimeMillis(); 
     target = searchFileRecursive(new File(rootFolder), fileName); 
     System.out.println(target.getAbsolutePath()); 
     System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms"); 

     start = System.currentTimeMillis(); 
     target = searchFileByDeepness(rootFolder, fileName); 
     System.out.println(target.getAbsolutePath()); 
     System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms"); 
    } 


    // Solution with FileUtils#listFiles 
    //-------------------------------------------- 

    public static File searchFileWithFileUtils(final File file, final String fileName) { 
     File target = null; 
     if(file.isDirectory()) { 
      Collection<File> files = FileUtils.listFiles(file, null, true); 
      for (File currFile : files) { 
       if (currFile.isFile() && currFile.getName().equals(fileName)) { 
        target = currFile; 
        break; 
       } 
      } 
     } 
     return target; 
    } 


    // Recursive solution 
    //-------------------------------------------- 

    public static File searchFileRecursive(final File file, final String search) { 
     if (file.isDirectory()) { 
      File[] files = file.listFiles(); 
      for (File f : files) { 
       File target = searchFileRecursive(f, search); 
       if(target != null) { 
        return target; 
       } 
      } 
     } else { 
      if (search.equals(file.getName())) { 
       return file; 
      } 
     } 
     return null; 
    } 


    // Fastest solution 
    //-------------------------------------------- 

    public static File searchFileByDeepness(final String directoryName, final String fileName) { 
     File target = null; 
     if(directoryName != null && fileName != null) { 
      File directory = new File(directoryName); 
      if(directory.isDirectory()) { 
       File file = new File(directoryName, fileName); 
       if(file.isFile()) { 
        target = file; 
       } 
       else { 
        List<File> subDirectories = getSubDirectories(directory); 
        do { 
         List<File> subSubDirectories = new ArrayList<File>(); 
         for(File subDirectory : subDirectories) { 
          File fileInSubDirectory = new File(subDirectory, fileName); 
          if(fileInSubDirectory.isFile()) { 
           return fileInSubDirectory; 
          } 
          subSubDirectories.addAll(getSubDirectories(subDirectory)); 
         } 
         subDirectories = subSubDirectories; 
        } while(subDirectories != null && ! subDirectories.isEmpty()); 
       } 
      } 
     } 
     return target; 
    } 

    private static List<File> getSubDirectories(final File directory) { 
     File[] subDirectories = directory.listFiles(new FilenameFilter() { 
      @Override 
      public boolean accept(final File current, final String name) { 
       return new File(current, name).isDirectory(); 
      } 
     }); 
     return Arrays.asList(subDirectories); 
    } 
} 

परिणाम:

searchFileWithFileUtils: 20186ms | searchFileRecursive: 1134ms | searchFileByDeepness: 16ms


[संपादित करें] तुम भी जावा 8 फ़ाइलें एपीआई का उपयोग कर सकते हैं यह काम कर रहे हैं:

public static File searchFileJava8(final String rootFolder, final String fileName) { 
    File target = null; 
    Path root = Paths.get(rootFolder); 
    try (Stream<Path> stream = Files.find(root, Integer.MAX_VALUE, (path, attr) -> 
      path.getFileName().toString().equals(fileName))) { 
     Optional<Path> path = stream.findFirst(); 
     if(path.isPresent()) { 
      target = path.get().toFile(); 
     } 
    } 
    catch (IOException e) { 
    } 
    return target; 
} 

लेकिन निष्पादन समय बेहतर नहीं (994ms) है।

संबंधित मुद्दे