[JAVA] Demo-Code, der Verzeichnisse mit Files.walkFileTree rekursiv durchsucht

Überblick

Das rekursive Durchsuchen von Verzeichnissen in Java kann mithilfe der in Java 1.7 eingeführten Methode "Files.walkFileTree" problemlos implementiert werden. Verwenden Sie außerdem eine Klasse, die die "FileVisitor" -Schnittstelle implementiert, um eine beliebige Verarbeitung für jede durchsuchte Datei oder jedes gesuchte Verzeichnis durchzuführen.

walkFileTree

Übergeben Sie den Pfad, der der Startpunkt der Suche ist, am Anfang des ersten Arguments und die Instanz von FileVisitor am zweiten Argument.

walkFileTree


public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor) throws IOException {
  // ...
}

Umgebung

Referenz

Demo-Code für die rekursive Verarbeitung

In diesem Demo-Code werden die relativen Pfade (vom Startpfad) der Dateien und Verzeichnisse unter dem zu durchsuchenden Startpfad erfasst und in einer Liste zusammengefasst. Im Falle einer Datei berechnet MD5 die Prüfsumme.

ComputeFileChecksumVisitor

Die SimpleFileVisitor-Klasse ist eine grundlegende Visitor-Klasse, die die FileVisitor-Schnittstelle implementiert. Erben Sie diese Klasse, um die Verarbeitung für Dateien und Verzeichnisse zu implementieren.

Operationen an Dateien

Die überschriebene "visitFile" ist eine Methode, die für jede durchsuchte Datei zurückgerufen wird. Hier wird der Prozess zum Abrufen des relativen Pfads der Datei und zum Berechnen der Prüfsumme implementiert.

Operationen an Verzeichnissen

Die Methode "preVisitDirectory" ist eine Methode, die für jedes durchsuchte Verzeichnis zurückgerufen wird. Da die Prüfsumme nicht im Verzeichnis berechnet wird, wird nur der relative Pfad erfasst. Darüber hinaus gibt es auch eine Methode namens "postVisitDirectory" für Operationen an Verzeichnissen, die sich jedoch zu dem Zeitpunkt unterscheidet, zu dem sie zurückgerufen wird, da der Methodenname "pre", "post" hat. ..

Code

ComputeFileChecksumVisitor


import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

public class ComputeFileChecksumVisitor extends SimpleFileVisitor<Path> {

	private final Path start;
	private final String hashAlg;
	private final List<FileItem> items = new ArrayList<>();

	public ComputeFileChecksumVisitor(Path start, String hashAlg) {
		this.start = start;
		this.hashAlg = hashAlg;
	}

	public List<FileItem> getResult() {
		return items;
	}

	@Override
	public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
		if (!dir.equals(start)) {
			FileItem item = new FileItem(relativePath(dir), "");
			items.add(item);
		}
		return FileVisitResult.CONTINUE;
	}

	@Override
	public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
		FileItem item = new FileItem(relativePath(file), checksum(file));
		items.add(item);
		return FileVisitResult.CONTINUE;
	}

	private Path relativePath(Path path) {
		if (path.startsWith(start)) {
			return path.subpath(start.getNameCount(), path.getNameCount());
		}
		throw new RuntimeException();
	}

	private String checksum(Path path) throws IOException {
		MessageDigest digest = null;
		try {
			digest = MessageDigest.getInstance(hashAlg);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
		try (InputStream input = Files.newInputStream(path);
			 DigestInputStream dInput = new DigestInputStream(input, digest)) {
			while (dInput.read() != -1) {}
		}
		return toHex(digest.digest());
	}

	private String toHex(byte[] bytes) {
		StringBuilder builder = new StringBuilder(bytes.length * 2);
		for (byte b : bytes) {
			builder.append(String.format("%02x", b));
			//builder.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
		}
		return builder.toString();
	}

}

FileItem

ComputeFileChecksum Diese Klasse speichert Informationen zu Dateien und Verzeichnissen, die von Visitor durchsucht werden. Das Feld "Pfad" speichert den relativen Pfad (vom Ursprungspfad) der durchsuchten Datei oder des gesuchten Verzeichnisses. Das Feld "Prüfsumme" speichert die Prüfsumme der durchsuchten Datei oder ein Leerzeichen im Fall eines Verzeichnisses.

Code

FileItem


import java.nio.file.Path;

public class FileItem implements Comparable<FileItem> {
	private Path path;
	private String checksum;

	public FileItem(Path path, String checksum) {
		this.path = path;
		this.checksum = checksum;
	}

	public Path getPath() {
		return path;
	}
	public String getChecksum() {
		return checksum;
	}

	@Override
	public int compareTo(FileItem o) {
		return this.compareTo(o);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((checksum == null) ? 0 : checksum.hashCode());
		result = prime * result + ((path == null) ? 0 : path.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		FileItem other = (FileItem) obj;
		if (checksum == null) {
			if (other.checksum != null)
				return false;
		} else if (!checksum.equals(other.checksum))
			return false;
		if (path == null) {
			if (other.path != null)
				return false;
		} else if (!path.equals(other.path))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "FileItem [path=" + path + ", checksum=" + checksum + "]";
	}

}

Demo

Ich habe die Verzeichnisse dir1 und dir2 mit der gleichen Verzeichnisstruktur wie unten gezeigt erstellt. Der Dateiname und der Inhalt der Datei sind identisch, aber die Zeitstempel des Erstellungsdatums und der Erstellungszeit sind unterschiedlich. Suchen Sie im Democode nach diesen "dir1" und "dir2", um eine Liste der Dateien, Verzeichnisse und eine Prüfsumme der Dateien zu erhalten, um zu überprüfen, ob sie dieselbe Struktur haben.

D:var
├─dir1
│  │  test1.txt
│  │  test2.txt
│  │
│  ├─aaa
│  │  └─ddd
│  ├─bbb
│  │      test3.txt
│  │
│  └─ccc
│          test4.txt
│
└─dir2
    │  test1.txt
    │  test2.txt
    │
    ├─aaa
    │  └─ddd
    ├─bbb
    │      test3.txt
    │
    └─ccc
            test4.txt

Lauf

Demo


import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class Demo {

	public static void main(String[] args) throws Exception {

		Path dir1 = Paths.get("D:", "var", "dir1");
		ComputeFileChecksumVisitor dir1Visit = new ComputeFileChecksumVisitor(dir1, "MD5");
		Files.walkFileTree(dir1, dir1Visit);

		Path dir2 = Paths.get("D:", "var", "dir2");
		ComputeFileChecksumVisitor dir2Visit = new ComputeFileChecksumVisitor(dir2, "MD5");
		Files.walkFileTree(dir2, dir2Visit);

		List<FileItem> dir1Files = dir1Visit.getResult();
		System.out.println("Root : " + dir1.toString());
		dir1Files.forEach(System.out::println);

		List<FileItem> dir2Files = dir2Visit.getResult();
		System.out.println("Root : " + dir2.toString());
		dir2Files.forEach(System.out::println);

		if (dir1Files.equals(dir2Files)) {
			System.out.println("equal");
		} else {
			System.out.println("not equal");
		}
	}

}

Ergebnis der Ausführung

Root : D:\var\dir1
FileItem [path=aaa, hash=]
FileItem [path=aaa\ddd, hash=]
FileItem [path=bbb, hash=]
FileItem [path=bbb\test3.txt, hash=ed6e956a3d549303751e3238ab04bb46]
FileItem [path=ccc, hash=]
FileItem [path=ccc\test4.txt, hash=2c97af7af48689fc67a2700d9f051af6]
FileItem [path=test1.txt, hash=ac6a2aaa9317ef1f007c092c6a5fd75e]
FileItem [path=test2.txt, hash=811ad90a8dafc585bb64b23b6200969e]
Root : D:\var\dir2
FileItem [path=aaa, hash=]
FileItem [path=aaa\ddd, hash=]
FileItem [path=bbb, hash=]
FileItem [path=bbb\test3.txt, hash=ed6e956a3d549303751e3238ab04bb46]
FileItem [path=ccc, hash=]
FileItem [path=ccc\test4.txt, hash=2c97af7af48689fc67a2700d9f051af6]
FileItem [path=test1.txt, hash=ac6a2aaa9317ef1f007c092c6a5fd75e]
FileItem [path=test2.txt, hash=811ad90a8dafc585bb64b23b6200969e]
equal

Recommended Posts

Demo-Code, der Verzeichnisse mit Files.walkFileTree rekursiv durchsucht
Beispielcode zum Aufrufen der Yahoo! Local Search API in Java
So implementieren Sie Suchfunktionen in Rails
Beispielcode zum Aufrufen der Yahoo! Shopping Product Search (v3) -API mit Spring RestTemplate
Farbcodierung der Konsolenausgabe in Eclipse
Code zum Escapezeichen von JSON-Zeichenfolgen in Java
Suchmethode
So implementieren Sie UICollectionView mit Code nur in Swift
Beispielcode zum Konvertieren von List in List <String> in Java Stream
Ausgabeeinstellungen an die Debug-Konsole in Visual Studio Code
So zeigen Sie eine Browser-Vorschau mit VS-Code an
So schreiben Sie eine Datumsvergleichssuche in Rails