Java переместить подкаталог с файлами и структурой в родительский каталог - PullRequest
1 голос
/ 21 марта 2019

Попытка переместить файлы из подкаталога вместе со структурой в родительский каталог. И я не могу сделать это, используя Files.move(). Чтобы проиллюстрировать проблему, см. Ниже структуру каталогов.

$ tree
.
└── b
    ├── c
    │   ├── cfile.gtxgt
    │   └── d
    │       ├── dfile.txt
    │       └── e
    └── x
        └── y
            └── z
                ├── 2.txt
                └── p
                    ├── file1.txt
                    └── q
                        ├── file
                        ├── file2.txt
                        └── r
                            └── 123.txt

Я хочу эмулировать приведенную ниже команду перемещения через Java.

$ mv b/x/y/z/* b/c
b/x/y/z/2.txt -> b/c/2.txt
b/x/y/z/p -> b/c/p

И на выходе должно быть что-то похожее на

$ tree
.
└── b
    ├── c
    │   ├── 2.txt
    │   ├── cfile.gtxgt
    │   ├── d
    │   │   ├── dfile.txt
    │   │   └── e
    │   └── p
    │       ├── file1.txt
    │       └── q
    │           ├── file
    │           ├── file2.txt
    │           └── r
    │               └── 123.txt
    └── x
        └── y
            └── z

При этом все файлы и каталоги в каталоге z были перемещены в c.

Я пытался сделать это:

public static void main(String[] args) throws IOException{
    String aPath = "/tmp/test/a/";
    String relativePathTomove = "b/x/y/z/";
    String relativePathToMoveTo = "b/c";

    Files.move(Paths.get(aPath, relativePathTomove), Paths.get(aPath, relativePathToMoveTo), StandardCopyOption.REPLACE_EXISTING);

}

Однако это вызывает это исключение для брошенного java.nio.file.DirectoryNotEmptyException: /tmp/test/a/b/c, и если опция REPLACE_EXISTING удалена, код выдает java.nio.file.FileAlreadyExistsException: /tmp/test/a/b/c.

Этот вопрос содержит ответ, который использует рекурсивную функцию для решения этой проблемы. Но в моем случае это потребует дополнительной сложности, так как мне нужно даже заново создать структуру sub-dir в новом месте.

Я не пробовал использовать служебный метод commons-io org.apache.commons.io.FileUtils#moveDirectoryToDirectory, поскольку этот код сначала копирует файлы, а затем удаляет их из исходного местоположения. И в моем случае файлы огромны, и, следовательно, это не предпочтительный вариант.

Как я могу достичь функциональности перемещения в Java, не прибегая к копированию. Мой единственный вариант перемещения отдельных файлов?

TLDR: как я могу эмулировать функциональность mv в java для перемещения sub dir с файлами и структурой в родительский каталог.

1 Ответ

0 голосов
/ 25 марта 2019

Я закончил тем, что сделал это:

Создайте FileVisitor Реализацию следующим образом:

package com.test.files;

import org.apache.log4j.Logger;

import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Objects;

import static java.nio.file.FileVisitResult.TERMINATE;


public class MoveFileVisitor implements FileVisitor<Path> {

    private static final Logger LOGGER = Logger.getLogger(MoveFileVisitor.class);
    private final Path target;
    private final Path source;

    public MoveFileVisitor(@NotNull Path source, @NotNull Path target) {
        this.target = Objects.requireNonNull(target);
        this.source = Objects.requireNonNull(source);
    }

    @Override
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
        Path relativePath = source.relativize(dir);
        Path finalPath = target.resolve(relativePath);
        Files.createDirectories(finalPath);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        Path relativePath = source.relativize(file);
        Path finalLocation = target.resolve(relativePath);
        Files.move(file, finalLocation);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) {
        LOGGER.error("Failed to visit file during move" + file.toAbsolutePath(), exc);
        return TERMINATE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
        Files.delete(dir);
        return FileVisitResult.CONTINUE;
    }


}

И затем пройдитесь по этому Посетителю следующим образом:

    String source = "/temp/test/a/b/x/y/z";
    String target = "/temp/test/a/b/c";

    MoveFileVisitor visitor = new MoveFileVisitor(Paths.get(source), Paths.get(target));
    Files.walkFileTree(Paths.get(source), visitor);
...