001// SPDX-License-Identifier: GPL-3.0-or-later 002 003package es.uvigo.esei.sing.textproc.step.util; 004 005import java.io.IOException; 006import java.nio.file.FileVisitOption; 007import java.nio.file.FileVisitResult; 008import java.nio.file.Files; 009import java.nio.file.Path; 010import java.nio.file.SimpleFileVisitor; 011import java.nio.file.attribute.BasicFileAttributes; 012import java.util.EnumSet; 013 014import lombok.AccessLevel; 015import lombok.NoArgsConstructor; 016import lombok.NonNull; 017 018/** 019 * This class contains static utility methods for manipulating filesystem 020 * objects that don't belong to the responsibilities of a single class. 021 * 022 * @author Alejandro González García 023 */ 024@NoArgsConstructor(access = AccessLevel.PRIVATE) 025public final class PathUtil { 026 /** 027 * Attempts a best effort to clean up the file tree whose root is at the 028 * specified path (that is, all the files and directories inside a directory, 029 * like {@code rm -rf} does on Unix systems). Any I/O error that occurs is 030 * silently discarded. 031 * 032 * @param root The root location of file system (sub)tree that will be deleted. 033 * @throws IllegalArgumentException If {@code root} is {@code null}. 034 */ 035 public static void deletePathRecursively(@NonNull final Path root) { 036 try { 037 Files.walkFileTree(root, new SimpleFileVisitor<Path>() { 038 @Override 039 public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { 040 // Ignore that the file doesn't exist, because another process deleted it 041 // or whatever 042 Files.deleteIfExists(file); 043 044 return FileVisitResult.CONTINUE; 045 } 046 047 @Override 048 public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException { 049 // Delete the directory itself after its entries are deleted 050 Files.deleteIfExists(dir); 051 052 return FileVisitResult.CONTINUE; 053 } 054 }); 055 } catch (final IOException ignored) {} 056 } 057 058 /** 059 * Returns an approximation to the total disk space consumed by a file tree 060 * whose root is at the specified path (in other words, the total disk space 061 * consumed by all the files inside a directory, including files in 062 * subdirectories). 063 * <p> 064 * If an I/O error occurs while processing a file or directory, which can be 065 * caused, for instance, by insufficient permissions to read it, it won't be 066 * counted for the total. On the other hand, even if no I/O error occurs, it is 067 * not guaranteed that the resulting number is the exact total size of the files 068 * in the file system because of transparent compression, sparse files and so 069 * on. Also, symbolic links are resolved. 070 * </p> 071 * 072 * @param root The root location of file system (sub)tree whose size will be 073 * computed. 074 * @return The total approximate size of the disk space consumed by the 075 * (sub)tree, in bytes. 076 * @throws IllegalArgumentException If {@code root} is {@code null}. 077 */ 078 public static long getTotalPathSize(@NonNull final Path root) { 079 final VariableHolder<Long> totalSize = new VariableHolder<>(0L); 080 081 try { 082 Files.walkFileTree( 083 root, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, 084 new SimpleFileVisitor<Path>() { 085 @Override 086 public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { 087 // Ignore named pipes and such 088 if (attrs.isRegularFile()) { 089 totalSize.setVariable(totalSize.getVariable() + attrs.size()); 090 } 091 092 return FileVisitResult.CONTINUE; 093 } 094 095 @Override 096 public FileVisitResult visitFileFailed(final Path file, final IOException exc) throws IOException { 097 // Ignore failures 098 return FileVisitResult.CONTINUE; 099 } 100 101 @Override 102 public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException { 103 // Ignore failures 104 return FileVisitResult.CONTINUE; 105 } 106 } 107 ); 108 } catch (final IOException ignored) {} 109 110 return totalSize.getVariable(); 111 } 112}