Перемещение не пустого каталога рекурсивно с использованием Java NIO.2 FileVisitor и Files.walkFileTree(...)
Я видел много примеров того, как рекурсивно копировать или удалять файлы с помощью Java NIO.2. Например, вот как скопировать папку со всем ее содержимым:
/**
* Copies a folder with all contents recursively. Class implements
* {@code FileVisitor} interface.
* @author Ernestas Gruodis
*/
public static class TreeCopy implements FileVisitor<Path> {
private final Path source;
private final Path target;
private final boolean replace;
private final CopyOption[] options;
private final ArrayList<Object[]> events = new ArrayList<>();
/**
* Copies a folder with all contents recursively.
*
* @param source source file path.
* @param target target file path.
* @param replace {@code true} if existing file should be replaced.
*/
public TreeCopy(Path source, Path target, boolean replace) {
this.source = source;
this.target = target;
this.replace = replace;
options = replace ? new CopyOption[]{COPY_ATTRIBUTES, REPLACE_EXISTING} : new CopyOption[0];
}
@Override
public synchronized FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
Path newDir = target.resolve(source.relativize(dir));
try {
Files.copy(dir, newDir, options);
} catch (FileAlreadyExistsException ex) {
if (!replace) {
events.add(new Object[]{"Folder already exists", newDir, ex});
return FileVisitResult.TERMINATE;
} else {
return FileVisitResult.CONTINUE;
}
} catch (DirectoryNotEmptyException ex) {
//Ignore
} catch (IOException ex) {
events.add(new Object[]{"Unable to create a folder", newDir, ex});
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
@Override
public synchronized FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
Path newFile = target.resolve(source.relativize(file));
try {
Files.copy(file, newFile, options);
} catch (FileAlreadyExistsException ex) {
events.add(new Object[]{"File already exists", newFile, ex});
} catch (NoSuchFileException ex) {
events.add(new Object[]{"No such file", newFile.getParent(), ex});
} catch (IOException ex) {
events.add(new Object[]{"Unable to create a file", newFile, ex});
}
return FileVisitResult.CONTINUE;
}
@Override
public synchronized FileVisitResult postVisitDirectory(Path dir, IOException exc) {
if (exc == null) {
Path newDir = target.resolve(source.relativize(dir));
try {
FileTime time = Files.getLastModifiedTime(dir);
Files.setLastModifiedTime(newDir, time);
} catch (IOException ex) {
events.add(new Object[]{"Unable to copy all attributes to", newDir, ex});
}
}
return FileVisitResult.CONTINUE;
}
@Override
public synchronized FileVisitResult visitFileFailed(Path file, IOException ex) {
if (ex instanceof FileSystemLoopException) {
events.add(new Object[]{"Cycle detected", file, ex});
} else {
events.add(new Object[]{"Unable to copy", file, ex});
}
return FileVisitResult.CONTINUE;
}
/**
* Returns errors which happened while copying a directory.
*
* @return {@code ArrayList<Object[]>} error list, where at each entry
* of {@code Object[]} index:
* <ul><li> 0 - {@code String} - error description;
* </li><li> 1 - {@code Path} - target folder/file path;
* </li><li> 2 - {@code Exception} - specific exception.
* </li></ul>
*/
public ArrayList<Object[]> getEvents() {
return events;
}
}
Path source = Paths.get("/toCopyDir"),
target = Paths.get("/someDir2/etc/toCopyDir");
EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
TreeCopy tc = new TreeCopy(source, target, true);
try {
Files.walkFileTree(source, opts, Integer.MAX_VALUE, tc);
} catch (IOException ex) {
//Handle exception
}
Но как переместить папку, содержащую файлы? Есть метод Files.move(Path source, Path target, CopyOption... options) throws IOException
, Кто-нибудь может привести реальный эффективный пример?
Я думаю, что решение может быть использовать Files.copy(...)
в preVisitDirectory(...)
, а потом Files.delete(...)
в postVisitDirectory(...)
, что-то вроде того..
0 ответов
Вот решение:
def moveDir(path: Path, to: Path): Unit = {
Files.createDirectories(to)
Files.walkFileTree(
path,
new SimpleFileVisitor[Path] {
override def preVisitDirectory(
dir: Path,
attrs: BasicFileAttributes): FileVisitResult = {
val targetDir = to.resolve(path.relativize(dir))
try Files.createDirectory(targetDir)
catch {
case e: FileAlreadyExistsException =>
if (!Files.isDirectory(targetDir)) throw e
}
FileVisitResult.CONTINUE
}
override def visitFile(file: Path,
attrs: BasicFileAttributes): FileVisitResult = {
Files.move(file, to.resolve(path.relativize(file)))
FileVisitResult.CONTINUE
}
}
)
}