All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.core.io.file.PathMover Maven / Gradle / Ivy

Go to download

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

There is a newer version: 5.8.34
Show newest version
package cn.hutool.core.io.file;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.file.visitor.MoveVisitor;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;

import java.io.IOException;
import java.nio.file.*;

/**
 * 文件移动封装
 *
 * @author looly
 * @since 5.8.14
 */
public class PathMover {

	/**
	 * 创建文件或目录移动器
	 *
	 * @param src        源文件或目录
	 * @param target     目标文件或目录
	 * @param isOverride 是否覆盖目标文件
	 * @return {@code PathMover}
	 */
	public static PathMover of(final Path src, final Path target, final boolean isOverride) {
		return of(src, target, isOverride ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{});
	}

	/**
	 * 创建文件或目录移动器
	 *
	 * @param src     源文件或目录
	 * @param target  目标文件或目录
	 * @param options 移动参数
	 * @return {@code PathMover}
	 */
	public static PathMover of(final Path src, final Path target, final CopyOption[] options) {
		return new PathMover(src, target, options);
	}

	private final Path src;
	private final Path target;
	private final CopyOption[] options;

	/**
	 * 构造
	 *
	 * @param src     源文件或目录,不能为{@code null}且必须存在
	 * @param target  目标文件或目录
	 * @param options 移动参数
	 */
	public PathMover(final Path src, final Path target, final CopyOption[] options) {
		Assert.notNull(target, "Src path must be not null !");
		if(false == PathUtil.exists(src, false)){
			throw new IllegalArgumentException("Src path is not exist!");
		}
		this.src = src;
		this.target = Assert.notNull(target, "Target path must be not null !");
		this.options = ObjUtil.defaultIfNull(options, new CopyOption[]{});;
	}

	/**
	 * 移动文件或目录到目标中,例如:
	 * 
    *
  • 如果src和target为同一文件或目录,直接返回target。
  • *
  • 如果src为文件,target为目录,则移动到目标目录下,存在同名文件则按照是否覆盖参数执行。
  • *
  • 如果src为文件,target为文件,则按照是否覆盖参数执行。
  • *
  • 如果src为文件,target为不存在的路径,则重命名源文件到目标指定的文件,如move("/a/b", "/c/d"), d不存在,则b变成d。
  • *
  • 如果src为目录,target为文件,抛出{@link IllegalArgumentException}
  • *
  • 如果src为目录,target为目录,则将源目录及其内容移动到目标路径目录中,如move("/a/b", "/c/d"),结果为"/c/d/b"
  • *
  • 如果src为目录,target为不存在的路径,则重命名src到target,如move("/a/b", "/c/d"),结果为"/c/d/",相当于b重命名为d
  • *
* * @return 目标文件Path */ public Path move() { final Path src = this.src; Path target = this.target; final CopyOption[] options = this.options; if (PathUtil.isSub(src, target)) { if(Files.exists(target) && PathUtil.equals(src, target)){ // issue#2845,当用户传入目标路径与源路径一致时,直接返回,否则会导致删除风险。 return target; } // 当用户将文件夹拷贝到其子文件夹时,报错 throw new IllegalArgumentException(StrUtil.format("Target [{}] is sub path of src [{}]!", target, src)); } if (PathUtil.isDirectory(target)) { // 创建子路径的情况,1是目标是目录,需要移动到目录下,2是目标不能存在,自动创建目录 target = target.resolve(src.getFileName()); } // 自动创建目标的父目录 PathUtil.mkParentDirs(target); try { return Files.move(src, target, options); } catch (final IOException e) { if (e instanceof FileAlreadyExistsException || e instanceof AccessDeniedException) { // issue#I4QV0L@Gitee issue#I95CLT@Gitee // FileAlreadyExistsException 目标已存在 // AccessDeniedException 目标已存在且只读 throw new IORuntimeException(e); } // 移动失败,可能是跨分区移动导致的,采用递归移动方式 walkMove(src, target, options); // 移动后删除空目录 PathUtil.del(src); return target; } } /** * 移动文件或目录内容到目标中,例如: *
    *
  • 如果src为文件,target为目录,则移动到目标目录下,存在同名文件则按照是否覆盖参数执行。
  • *
  • 如果src为文件,target为文件,则按照是否覆盖参数执行。
  • *
  • 如果src为文件,target为不存在的路径,则重命名源文件到目标指定的文件,如moveContent("/a/b", "/c/d"), d不存在,则b变成d。
  • *
  • 如果src为目录,target为文件,抛出{@link IllegalArgumentException}
  • *
  • 如果src为目录,target为目录,则将源目录下的内容移动到目标路径目录中,源目录不删除。
  • *
  • 如果src为目录,target为不存在的路径,则创建目标路径为目录,将源目录下的内容移动到目标路径目录中,源目录不删除。
  • *
* * @return 目标文件Path */ public Path moveContent() { final Path src = this.src; if (PathUtil.isExistsAndNotDirectory(target, false)) { // 文件移动调用move方法 return move(); } final Path target = this.target; if (PathUtil.isExistsAndNotDirectory(target, false)) { // 目标不能为文件 throw new IllegalArgumentException("Can not move dir content to a file"); } // issue#2893 target 不存在导致NoSuchFileException if (PathUtil.equals(src, target)) { // issue#2845,当用户传入目标路径与源路径一致时,直接返回,否则会导致删除风险。 return target; } final CopyOption[] options = this.options; // 自动创建目标的父目录 PathUtil.mkParentDirs(target); // 移动失败,可能是跨分区移动导致的,采用递归移动方式 walkMove(src, target, options); return target; } /** * 递归移动 * * @param src 源目录 * @param target 目标目录 * @param options 移动参数 */ private static void walkMove(final Path src, final Path target, final CopyOption... options) { try { // 移动源目录下的内容而不删除目录 Files.walkFileTree(src, new MoveVisitor(src, target, options)); } catch (final IOException e) { throw new IORuntimeException(e); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy