如何找到所有独特的文件扩展名在Java中找到文件夹层次结构

问题描述:

什么是漫步文件夹层次结构并获取unqiue扩展名列表的最有效方式?如何找到所有独特的文件扩展名在Java中找到文件夹层次结构

这与this question非常相似,除了我想从Java内部完成。

有一个明显的递归解决方案检查File.isDirectory(),迭代所有孩子,检查每个扩展和isDirectory,然后保持一个唯一的集合(如一个集合),但我试图看看是否有更高效的一点。

定制的FileFilter:

public class FileExtensionFilter implements FilenameFilter { 
    private Set<String> filteredExtensions; 
    public FileExtensionFilter() { 
     filteredExtensions = new HashSet<String>(); 
    } 
    @Override 
    public boolean accept(File dir, String name) { 
     boolean accept = true; 
     for (String filteredExtension:filteredExtensions) { 
      accept = accept && !name.endsWith(filteredExtension); 
     } 
     return accept; 
    } 
    public void addFilteredExtension(String extension) { 
     filteredExtensions.add(extension); 
    } 
} 

递归方法解决:

public Set<String> checkForExtensions(File file) { 
    Set<String> extensions = new HashSet<String>(); 
    if (file.isDirectory()) { 
     for (File f : file.listFiles(fileExtensionFilter)) { 
      extensions.addAll(checkForExtensions(f)); 
     } 
    } else { 
     //NOTE: if you don't want the '.' in the extension you'll need to add a '+1' to the substring call 
     String extension = file.getName().substring(Math.max(file.getName().lastIndexOf('.'),0)); 
     extensions.add(extension); 
     fileExtensionFilter.addFilteredExtension(extension); 
    } 
    return extensions; 
} 

本来我没有Fil的解决方案eExtensionFilter,但注意到我可以通过动态添加过滤来提高效率。节省是指数级的。我从47秒降到700毫秒。

由于FileExtensionFilter将包含Set中所有扩展的重复副本,因此您可以通过消除Set all来清理内存使用情况。

没有更高效的一个。该算法将不得不测试每个文件,如果它的扩展名是一个,这是以前从未见过的。所以最好的算法将具有O(n)的复杂性。

根据我的观点,递归到所有目录中,并将所有文件的文件放在Set中是最好的。


显着的性能增益可能无法正常期运用一个HashMap的副作用;)我明白了,你在整个集迭代使用contains方法代替。如果你的原始版本是是真的,那么对我来说,这个表现是有问题的。

我仍然期望,即提取的扩展,只是将它们添加到HashSet是最高效的解决方案:

static String[] filenames = { "edit.txt", "my.notes.txt", "sheet.xlxs", 
     ".bash", "README" }; 
static HashSet<String> exts = new HashSet<>(); 

public static void main(String[] args) { 
    // we add every extension to a hashset 
    for (String filename : filenames) { 
     exts.add(getExtension(filename)); 
    } 

    // just dumps the set contents 
    for (String ext: exts) { 
     System.out.println(ext); 
    } 
} 

private static String getExtension(String filename) { 
    String ext = ""; 

    // calculate the index only once 
    int lastIndexOfDot = filename.lastIndexOf('.'); 

    // "README" and ".bash" are files with no extension! 
    if (lastIndexOfDot > 0) { 
     exts.add(filename.substring(lastIndexOfDot)); 
    } 
    return ext; 
} 
+0

通过使用fileNameFilter发现了一个稍微改进的方法 – Randyaa 2012-03-25 07:18:53

+0

它只是隐藏了复杂性。 'FileNameFilter'也必须查看每个文件名。它仍然是'O(n)'。 – 2012-03-25 16:05:05

+0

我同意,但是一旦我添加了过滤器,我就看到了戏剧性的性能提升。也许使用这套设备真的是发生放缓的地方。 – Randyaa 2012-03-26 03:30:47