java nio: walkFileTree实现文件夹复制移动删除

从java 1.7开始,java提供了java.noi.file.Files类用于更方便的实现文件/文件夹操作。
在Files中提供了丰富的静态方法用于文件操作,Files也提供了文件移动和复制操作(Files.move,Files.copy),但是对于不为的空文件夹,不能调用Files.move,Files.copy实现文件夹下所有文件的复制和移动。
根据Files.move,Files.copy的说明,如果要移动/复制包含子目录的文件夹,需要用Files.walkFileTree方法配合Files.move,Files.copy来实现。以下是实现代码:

NioFileUtil.java

package net.gdface.iadb;

import java.io.IOException;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;

/**
 * 使用于NIO实现文件夹的复制/移动,删除<br>
 * 需要java 1.7以上版本支持
 * @author guyadong
 *
 */
public class NioFileUtil {
	/**
	 * 复制文件夹
	 * @param source
	 * @param target
	 * @param options
	 * @throws IOException
	 * @see {@link #operateDir(boolean, Path, Path, CopyOption...)}
	 */
	public static void copyDir(Path source, Path target, CopyOption... options) throws IOException{
		operateDir(false, source, target, options);
	}
	/**
	 * 移动文件夹
	 * @param source
	 * @param target
	 * @param options
	 * @throws IOException
	 * @see {@link #operateDir(boolean, Path, Path, CopyOption...)}
	 */
	public static void moveDir(Path source, Path target, CopyOption... options) throws IOException{
		operateDir(true, source, target, options);
	}
	/**
	 * 复制/移动文件夹
	 * @param move 操作标记,为true时移动文件夹,否则为复制
	 * @param source 要复制/移动的源文件夹
	 * @param target 源文件夹要复制/移动到的目标文件夹
	 * @param options 文件复制选项 
	 * @throws IOException
	 * @see Files#move(Path, Path, CopyOption...)
	 * @see Files#copy(Path, Path, CopyOption...)
	 * @see Files#walkFileTree(Path, java.nio.file.FileVisitor)
	 */
	public static void operateDir(boolean move,Path source, Path target, CopyOption... options) throws IOException{
		if(null==source||!Files.isDirectory(source))
			throw new IllegalArgumentException("source must be directory");
		Path dest = target.resolve(source.getFileName());
		// 如果相同则返回
		if(Files.exists(dest)&&Files.isSameFile(source, dest))return;
		// 目标文件夹不能是源文件夹的子文件夹
		// isSub方法实现参见另一篇博客 http://blog.csdn.net/10km/article/details/54425614
		if(isSub(source,dest))
			throw new IllegalArgumentException("dest must not  be sub directory of source");
		boolean clear=true;		
		for(CopyOption option:options)
			if(StandardCopyOption.REPLACE_EXISTING==option){
				clear=false;
				break;
			}
		// 如果指定了REPLACE_EXISTING选项则不清除目标文件夹
		if(clear)
			deleteIfExists(dest);
		Files.walkFileTree(source, 
				new SimpleFileVisitor<Path>() {
					
					@Override
					public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
						// 在目标文件夹中创建dir对应的子文件夹
						Path subDir = 0==dir.compareTo(source)?dest:dest.resolve(dir.subpath(source.getNameCount(), dir.getNameCount()));
						Files.createDirectories(subDir);
						return FileVisitResult.CONTINUE;
					}
	
					@Override
					public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
						if(move)
							Files.move(file, dest.resolve(file.subpath(source.getNameCount(), file.getNameCount())),options);
						else
							Files.copy(file, dest.resolve(file.subpath(source.getNameCount(), file.getNameCount())),options);
						return FileVisitResult.CONTINUE;
					}
	
					@Override
					public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
						// 移动操作时删除源文件夹
						if(move)
							Files.delete(dir);
						return super.postVisitDirectory(dir, exc);
					}
				});
	}

	/**
	 * 强制删除文件/文件夹(含不为空的文件夹)<br>
	 * @param dir
	 * @throws IOException
	 * @see Files#deleteIfExists(Path)
	 * @see Files#walkFileTree(Path, java.nio.file.FileVisitor)
	 */
	public static void deleteIfExists(Path dir) throws IOException {
		try {
			Files.deleteIfExists(dir);
		} catch (DirectoryNotEmptyException e) {
			Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
				@Override
				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
					Files.delete(file);
					return FileVisitResult.CONTINUE;
				}
	
				@Override
				public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
					Files.delete(dir);
					return super.postVisitDirectory(dir, exc);
				}
			});
		}
	}

}

测试代码

	public void testCopy() throws IOException{
		Path start = Paths.get("d:\\tmp\\storeroot\\origin");
		Path target = Paths.get("E:\\tmp\\storeroot");
		NioFileUtil.copyDir(start, target);
	}

关于Files.walkFileTree方法的使用说明,参见这篇博客《walkFileTree、FileVisitor(遍历文件/目录)》,说得很详细了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值