【问题标题】:Searching Large Directories for Multiple Folders - JAVA在大型目录中搜索多个文件夹 - JAVA
【发布时间】:2016-02-29 10:56:39
【问题描述】:

我希望能够搜索一个大目录,包括名为“online”的每个文件夹的所有子文件夹,并将找到的文件夹添加到列表中。 p>

换句话说:这个文件是一个文件夹吗?如果不忽略,如果是,此文件夹是否称为“在线”?如果是,则添加到列表中,如果未打开并循环浏览文件夹内容并重新开始。

我有一个脚本:

String fileType = "online";

private void buildList(File aFile) {
 if (aFile.isDirectory()) {

    if (fileName.contains(fileType)) {
        addToList(aFile);
    } else {
        for (File bFile : aFile.listFiles()) {
            buildList(bFile);
        }
    }
 }
}

这适用于小目录,但不适用于大目录,因为它已打开大量数组。它挂起并用完所有内存。

我愿意接受所有建议。仅限 JAVA,理想情况下与 JDK1.6 兼容。提前非常感谢您!!!!

编辑:

static long counter = 0L;
ArrayList<File> opFolders;


public final class DirectoryCollectorVisitor extends SimpleFileVisitor<Path> {

   private final List<Path> list;



   public DirectoryCollectorVisitor(final List<Path> list) {


      this.list = list;
    }

    @Override
    public FileVisitResult preVisitDirectory(final Path path, final BasicFileAttributes attrs) {
        counterPrintField.setText("" + counter++);
        if (path.getFileName().toString().contains("online")) {
            list.add(path);
            File aFile = path.toFile();
            opFolders.add(aFile);
        }
        return FileVisitResult.CONTINUE;
    }
}



private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {                                           

    JFileChooser chooser = jFileChooser1;
    chooser.setCurrentDirectory(new java.io.File("O:\\Prod\\Clients"));
    chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
    chooser.setAcceptAllFileFilterUsed(false);
    int returnVal = chooser.showOpenDialog(this);

    if (returnVal == chooser.APPROVE_OPTION) {
        File file = chooser.getSelectedFile();
        try {
            jTextArea1.setText(null);
            opFolders = new ArrayList<>();

            final Path baseDir = Paths.get(file.getAbsolutePath());
            final List<Path> dirList = new ArrayList<>();
            dirList.add(baseDir);

            final FileVisitor<Path> visitor = new DirectoryCollectorVisitor(dirList);
            Files.walkFileTree(baseDir, visitor);
            if(opFolders.isEmpty()){
                System.err.println("EMPTY");
            }
            for (File aFile : opFolders) {
                if (!aFile.isDirectory() && !aFile.getName().toLowerCase().endsWith(".db")) {
                    jTextArea1.append(aFile.getAbsolutePath() + "\n");

                }

            }

            jTextArea1.append("...COMPLETE...");
        } catch (Exception ex) {
            System.out.println("Problem accessing directory: " + file.getAbsolutePath());
        }
    } else {
        System.out.println("File access cancelled by user.");
    }

}

@fge 更新代码

【问题讨论】:

  • 仅限 Java 6?太糟糕了...如果您使用 Java 7+ 会有一个解决方案。使用 Java 6,您几乎是 SOL(无法懒惰地读取目录条目)。但是现在是 2015 年,所以必须提出一个问题:为什么是 Java 6?已经有好几年了,它已经走到了生命的尽头
  • 这很奇怪。定义Large Directories
  • @UmaKanth 这一点都不奇怪;想象一下一个目录层次结构,其中每个级别都有数十甚至数百个文件,并且您递归地遍历它们。由于File.listFiles() 返回一个数组,所以它别无选择,只能急切地填充数组,这会很快导致巨大的内存消耗。从 JSR 203 和 DirectoryStream 开始,这不再是问题。
  • 每个递归级别都会创建一个新的文件数组。仍然无法想象以这种方式遍历时会耗尽内存的目录层次结构。你能给出一些数字(目录深度、每个目录的平均文件数)吗?
  • 每个文件夹可能包含数百个其他文件夹,可能包含数百个等等。我并不坚持使用 JDK1.6,尽管 JDK1.6 解决方案更适合用于仅支持 JDK1.6 的单独 informatica 项目。

标签: java search directory subdirectory


【解决方案1】:

不幸的是,您说您仅限于 Java 6。鉴于该要求,无法使用 File API 来执行此操作。 .listFiles() 只能以急切的方式填充目录条目。

嗯,有一种方法...如果您使用类似 Unix 的操作系统,您可以使用 ProcessBuilder 并使用诸如 find -type d -name online 之类的命令从基本目录发出进程:

final File baseDir = ...;
final ProcessBuilder pb = new ProcessBuilder(
    "find", "-type", "d", "-name", "online"
);
pb.directory(baseDir);

final Process p = pb.start();
// use the Process' InputStream

如果您使用 Java 7+,您会更轻松;编写一个FileVisitor 来收集到一个列表中:

public final class DirectoryCollectorVisitor
    extends SimpleFileVisitor<Path>
{
    private final List<Path> list;

    public DirectoryCollectorVisitor(final List<Path> list)
    {
        this.list = list;
    }

    @Override
    public FileVisitResult previsitDirectory(final Path path, final BasicFileAttributes attrs)
    {
        if (path.getFileName().toString().equals("online"))
            list.add(path);
        return FileVisitResult.CONTINUE;
    }
}

// ...

final Path baseDir = Paths.get(...);
final List<Path> dirList = new ArrayList<>();
final FileVisitor<Path> visitor = new DirectoryCollectorVisitor(list);
Files.walkFileTree(baseDir, visitor);
// dirList is not filled with the entries

使用 Java 8,它变得更加简单:

private static final BiPredicate<Path, BasicFileAttributes> ONLINE_DIRS 
    = (path, attrs) -> attrs.isDirectory() 
    && path.getFileName().toString().equals("online");

// ...

final Path baseDir = Paths.get(...);
final List<Path> dirList;

try (
    final Stream<Path> stream = Files.find(baseDir, Integer.MAX_VALUE,
        ONLINE_DIRS);
) {
    dirList = stream.collect(Collectors.toList());
}

【讨论】:

  • 好的,Java 7 解决方案有些工作,但速度很慢。只需 1 分钟即可循环浏览 500 个文件。有什么建议可以改进吗?谢谢!!!
  • @ldhxvs 是总共 500 个文件还是 500 个结果?
  • 1 个目录共 534 个文件夹(2,326 个文件)
  • @ldhxvs 那是什么操作系统? 1分钟显然是一个不正常的时间。您可以粘贴您使用的代码吗?还有,如果你用Java 8,能不能试试Java 8的方案,看看有没有效果?
  • Windows 7 Professional 64 位,SP1,Intel i5-4590 3.3GHz,12GB 内存。
猜你喜欢
  • 2018-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
相关资源
最近更新 更多