3

次のディレクトリ構造があるとします

/root/dir
/root/dir/file1.txt
/root/dir/subdir
/root/dir/subdir/file2.txt

そして、次のビジターを使用するとします。

class MyFileVisitor extends SimpleFileVisitor<Path> {

  @Override
  public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
  throws IOException {
    if(Files.isDirectory(file)) {
      throw new IllegalStateException("WAT!? Visiting directory: "+file.toAbsolutePath().toString());
    }
    System.out.println("Visiting file: "+file.toAbsolutePath().toString());
    return super.visitFile(file, attrs);
  }

walkFileTree の単純なオーバーロードを使用すると、次のようになります。

Files.walkFileTree(Paths.get("/root/dir"), new MyFileVisitor());  

すべてが計画どおりに進み、次の出力が表示されます。

Visiting file: /root/dir/file1.txt
Visiting file: /root/dir/subdir/file2.txt

しかし、最大深度を設定しようとすると、状況が崩れ始めます。

Files.walkFileTree(Paths.get("/root/dir"), EnumSet.noneOf(FileVisitOption.class), 1, new MyFileVisitor());

出力:

Visiting file: /root/dir/file1.txt

java.lang.IllegalStateException: WAT!? Visting directory: /root/dir/subdir

これはバグだと確信していますが、最初にコミュニティに尋ねたいと思いました:何か欠けているものはありますか?これは実際に予期された動作ですか? ご確認ありがとうございます!

詳細:

java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
4

3 に答える 3

5

私はあなたのコードを少しいじって、いくつかの行を追加しました:

/*
 * (non-Javadoc)
 * 
 * @see java.nio.file.SimpleFileVisitor#preVisitDirectory(java.lang.Object,
 * java.nio.file.attribute.BasicFileAttributes)
 */
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
        throws IOException {
    System.out.println(Thread.currentThread().getStackTrace()[1] + " "
            + dir);
    return super.preVisitDirectory(dir, attrs);
}

/*
 * (non-Javadoc)
 * 
 * @see java.nio.file.SimpleFileVisitor#postVisitDirectory(java.lang.Object,
 * java.io.IOException)
 */
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
        throws IOException {
    System.out.println(Thread.currentThread().getStackTrace()[1] + " "
            + dir);
    return super.postVisitDirectory(dir, exc);
}

/*
 * (non-Javadoc)
 * 
 * @see java.nio.file.SimpleFileVisitor#visitFileFailed(java.lang.Object,
 * java.io.IOException)
 */
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc)
        throws IOException {
    System.out.println(Thread.currentThread().getStackTrace()[1] + " "
            + file);
    return super.visitFileFailed(file, exc);
}

何が起こっているのかを見るのは簡単です。

あなたがバグと呼ぶものはここで起こりますjava.nio.file.FileTreeWalker:134

    // at maximum depth or file is not a directory
    if (depth >= maxDepth || !attrs.isDirectory()) {
        return visitor.visitFile(file, attrs);
    }

最後に、私がそれについて思うこと:

1.: subdir は深さ 1 の一部です
2.: forestvisitFileディレクトリがなければ、それらがそこにあることさえ認識できません。

だから私はそれが通常の行動だと思います。

ちなみに、次のオーバーライドで attrs を使用できます。

@Override
public FileVisitResult visitFile(final Path file,
        final BasicFileAttributes attrs) throws IOException {
    if (attrs.isDirectory()) {
        throw new IllegalStateException("WAT!? Visiting directory: "
                + file.toAbsolutePath().toString());
    }
    System.out
            .println("Visiting file: " + file.toAbsolutePath().toString());
    return super.visitFile(file, attrs);
}
于 2014-01-02T20:19:59.127 に答える
2

この動作はFiles::walkFileTree のドキュメントで指定されているため、意図的なものであり、バグではありません。

ディレクトリを含む、maxDepth で検出されたすべてのファイルに対して、visitFile メソッドが呼び出されます。

ディレクトリvisitFileで呼び出されることを防ぐために、ディレクトリは、java.nio.fileクラスのドキュメント全体で暗黙的にファイルと呼ばれます。たとえば、Files::walkFileTreeそれ自体のドキュメントには、「このメソッドは、指定された開始ファイルをルートとするファイル ツリーをたどる」と記載されており、「開始ファイル」は (もちろん) directoryである可能性があります。

visitFileFailedまた、ドキュメントで説明されているように、ディレクトリでも呼び出される可能性があることに注意してください。

ファイルがディレクトリであり、ディレクトリを開くことができなかった場合、visitFileFailed メソッドが I/O 例外で呼び出されます。

Franz Ebner は、この動作が発生するコードを示しました。私は、彼がそれが意図的であると考えている理由に同意します。attrs通常のファイル (またはシンボリック リンク) のみが必要な場合は、パラメーターを使用してファイルの種類を確認することにも同意します。

于 2019-10-27T19:45:41.290 に答える