在目录及其子目录中,针对每个文件执行某项操作。

3
我需要对文件列表应用更复杂的逻辑。具体来说,当应用软件更新时,我想对从更新 zip 文件中获取的文件执行以下操作:
  • updateFile为更新存档中的文件,originalFile为当前版本文件,backupFile为原始文件的备份
  • 如果originalFile与当前运行的jar文件相同,则跳过它
  • 如果updateFile的父目录是特定名称,则跳过它(例如,包含用户数据的目录)

我希望有一些选项,例如为每个文件运行回调函数:

GreatFileLibrary.forEveryChildOf(new File("my path"), 
                                (File child)->{ ... logic here ... });

如果不行的话,至少把所有文件放在一个Collection中并循环遍历它:
Iterable<File> files = GreatFileLibrary.listChildren(new File("my path"));
for(File child:files) {
    ... logic ...
}

前者可以让我显示进度(通过知道列表长度),但我认为更新几乎是瞬间完成的。

当然,文件可以返回某些子元素列表,所以超级幼稚的方法是:

  /** Returns list of all child files, recursively. **/
  public static Iterable<File> listFileChildren(File parent, ArrayList<File> list) {
    File[] files = parent.listFiles();
    for(File file:files) {
      list.add(file);
      if(file.isDirectory())
        listFileChildren(file, list);
    }
    return list;
  }
  public static Iterable<File> listFileChildren(File parent) {
    return listFileChildren(parent, new ArrayList());
  }

Java 8的内置库是否可以更好地完成这项任务?我的代码有缺陷吗?我真的很希望能够消除将File[]转换为Iterable<File>的过程,因为这很不好。


我不知道你想在每个文件上做的事情有多复杂,但这看起来像是要使用shell脚本和find命令完成的。 - Walter Tross
@WalterTross 尽管我现在正在制作仅限于Windows的程序,但我尽可能地喜欢使用跨平台代码。而且,我从命令行运行的少数功能(获取加密UUID)实际上存在问题... - Tomáš Zato
我明白了 - 无论如何,Cygwin是你的好朋友。 - Walter Tross
4个回答

2

你的代码中创建列表将是最耗时的部分,因此尽量避免使用它。

一个简单的方法是:

public void forEveryChildOf(File file) {
    for(File child:file.listFiles())
        doForEach(file,child);
}

private void doForEach(File topParent,File child){
    if(child.isFile())
        System.out.println("Do logic");

    if(child.isDirectory())
        for(File subchild:child.listFiles())
            doForEach(topParent,subchild);
}

1
如果您不介意创建多个流对性能的影响,此函数将返回目标文件夹中每个子文件的流。
下面的版本使用Java 7的Files和Path类,因此您可能需要重写一些内容(或调用Path#toFile)。
public static Stream<Path> stream(Path path)  {
    try {
        return Files.isDirectory(path) ? Files.list(path).map(innerpath -> stream(innerpath)).flatMap(s -> s) : Stream.of(path);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

这个版本使用普通的文件(File
public static Stream<File> stream(File file)  {
    return file.isDirectory() ? Arrays.stream(file.listFiles()).map(innerfile -> stream(innerfile)).flatMap(s -> s) : Stream.of(file);
}

你可以在最终的Stream上收集到一个List,或者调用forEach

0
public void allFiles(File raiz) {          
   for (File arquivo : raiz.listFiles(filtro)) {
      if (arquivo.isFile()) {
          try {              
            System.out.println(arquivo);
          } catch (Exception e) {
            System.out.println("erro" +arquivo);
          }
      } else {
         allFiles(arquivo);
      } 
   }
}

0

FileVisitor 是来自 nio 的类:

    Path startPath = new File("...").toPath();
    Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException {
            //your logic

            return FileVisitResult.CONTINUE;
        }
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接