Java将包含文件和结构的子目录移动到父目录

Java将包含文件和结构的子目录移动到父目录,java,nio,Java,Nio,尝试将文件与结构一起从子目录移动到父目录。我无法使用Files.move()完成此操作。为了说明这个问题,请参见下面的目录结构 $ tree . └── b ├── c │   ├── cfile.gtxgt │   └── d │   ├── dfile.txt │   └── e └── x └── y └── z ├── 2.txt

尝试将文件与结构一起从子目录移动到父目录。我无法使用
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模拟下面的move命令

$ 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\u EXISTING
选项,则代码抛出
java.nio.file.filealreadyExistException:/tmp/test/a/b/c

这个问题的答案是使用递归函数来解决这个问题。但在我的情况下,它将涉及进一步的复杂性,因为我甚至需要在新位置重新创建sub-dir结构

我没有尝试使用
commons io
实用程序方法,因为这段代码似乎是先复制文件,然后从原始位置删除它们。在我的例子中,文件很大,因此这不是首选选项

如何在java中实现移动功能,而不必借助复制。个人文件移动是我唯一的选择吗

TLDR:如何在java中模拟
mv
功能,将带有文件和结构的子目录移动到父目录

我最后做了这样一件事:

创建一个
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;
    }


}
我最终做了这样的事:

创建一个
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;
    }


}

你不需要这些。只要一个
File.rename()
和正确的参数,就可以在一行代码中完成全部工作。@user207421-我想你指的是方法。此方法的文档建议使用
Files.move()
,它会引发上面列出的异常。另外,我不认为
renameTo
会考虑到目标目录中有一些文件,这里的文件需要合并到这些文件中。如果所有这些都是可能的,你能给我正确的参数。我不想为已经实现的东西编写代码,你不需要这些。只要一个
File.rename()
和正确的参数,就可以在一行代码中完成全部工作。@user207421-我想你指的是方法。此方法的文档建议使用
Files.move()
,它会引发上面列出的异常。另外,我不认为
renameTo
会考虑到目标目录中有一些文件,这里的文件需要合并到这些文件中。如果所有这些都是可能的,你能给我正确的参数。我讨厌为已经实现的东西编写代码。