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
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.
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.
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. ..
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.
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 + "]";
}
}
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