使用于NIO实现文件夹的复制/移动,删除

简介: 使用于NIO实现文件夹的复制/移动,删除

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
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;

import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

public class NioFileUtil {
    
    private static final Logger logger=Logger.getLogger(NioFileUtil.class);
    
    /**
     * 复制文件夹
     * @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(final boolean move,final Path source, Path target, final CopyOption... options) throws IOException{
        if(null==source||!Files.isDirectory(source))
            throw new IllegalArgumentException("source must be directory");
        final 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() {

                    @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);
                    }
                });
    }

    /**
     * 强制删除文件/文件夹(含不为空的文件夹)

     * @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() {
                @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);
                }
            });
        }
    }

    /**
     * 判断sub是否与parent相等或在其之下

     * parent必须存在,且必须是directory,否则抛出{@link IllegalArgumentException}
     * @param parent 
     * @param sub
     * @return
     * @throws IOException 
     */
    public static boolean sameOrSub(Path parent,Path sub) throws IOException{
        if(null==parent)
            throw new NullPointerException("parent is null");
        if(!Files.exists(parent)||!Files.isDirectory(parent))
            throw new IllegalArgumentException(String.format("the parent not exist or not directory %s",parent));
        while(null!=sub) {
            if(Files.exists(sub)&&Files.isSameFile(parent, sub))
                return true;
            sub=sub.getParent();
        }
        return false;   
    }
    /**
     * 判断sub是否在parent之下的文件或子文件夹

     * parent必须存在,且必须是directory,否则抛出{@link IllegalArgumentException}
     * @param parent
     * @param sub
     * @return
     * @throws IOException
     * @see {@link #sameOrSub(Path, Path)}
     */
    public static boolean isSub(Path parent,Path sub) throws IOException{
        return (null==sub)?false:sameOrSub(parent,sub.getParent());
    }
    
    /**获取路径的完整地址
     * @param subPaths
     * @return
     * @throws Exception
     */
    public static String fileAbsolutePath(String...subPaths) throws Exception{
        if(null == subPaths || subPaths.length == 0){
            throw new Exception("路径不能为空");
        }
        
        StringBuffer buffer=new StringBuffer();
        
        for(int i=0;i<subPaths.length;i++){
            
            String subPath=subPaths[i];
            if(StringUtils.isEmpty(subPath)){
                continue;
            }
            if(i != 0){
                subPath=subPath.replaceFirst("^(?:\\|/)*", "");
            }
            subPath=subPath.replaceFirst("(?:\\|/)*$", "");
            buffer.append(subPath).append("/");
        }
        buffer.deleteCharAt(buffer.length()-1);
        
        String path=buffer.toString();
        
        String absolutePath=new File(path).getAbsolutePath();
        return absolutePath;
    }
    
    /**读取文件内容
     * @param path
     * @return
     * @throws Exception
     */
    public static String readFileContent(String path) throws Exception{
        File file=new File(path);
        if(!file.exists()){
            throw new Exception(StringUtil.format("文件 {} 不存在,无法获取内容",path));
        }else if(!file.isFile()){
            throw new Exception(StringUtil.format("文件 {} 不是文件,无法获取内容", path));
        }else if(!file.canRead()){
            throw new Exception(StringUtil.format("文件 {} 没有读取权限", path));
        }
        
        StringBuffer buffer=new StringBuffer();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
            String tempString = null;
            // 一次读入一行,直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                buffer.append(tempString);
                buffer.append("\n");
            }
        } catch (IOException e) {
            logger.error(StringUtil.format("文件 {} 读取内容失败,{}", path,e.getMessage()));
            throw e;
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
        
        return buffer.toString();
    }
    
    /**读取文件内容写入输出流中
     * @param outputStream
     * @throws Exception
     */
    public static void readFileToOutputStream(String path,OutputStream outputStream) throws Exception{
        File file=new File(path);
        if(!file.exists()){
            throw new Exception(StringUtil.format("文件 {} 不存在,无法获取内容",path));
        }else if(!file.isFile()){
            throw new Exception(StringUtil.format("文件 {} 不是文件,无法获取内容", path));
        }else if(!file.canRead()){
            throw new Exception(StringUtil.format("文件 {} 没有读取权限", path));
        }
        
        byte[] b=new byte[1024];
        InputStream inputStream=null;
        int bCount=0;
        try{
            inputStream=new FileInputStream(file);
            
            while((bCount=inputStream.read(b))>0){
                outputStream.write(b, 0, bCount);
            }
            
        }catch(Exception e){
            logger.error(StringUtil.format("读取文件 {} 时出错,{}", path,e.getMessage()));
            throw e;
        }finally{
            if(null != inputStream){
                inputStream.close();
            }
        }
    }
    
    /**保存文件内容
     * @param path
     * @param fileContent
     * @param cover
     * @throws Exception
     */
    public static void saveFileContent(String path,String fileContent,boolean cover) throws Exception{
        File file=new File(path);
        if(!file.exists()){
            throw new Exception(StringUtil.format("文件 {} 不存在,无法获取内容",path));
        }else if(!file.isFile()){
            throw new Exception(StringUtil.format("文件 {} 不是文件,无法获取内容", path));
        }else if(!file.canRead()){
            throw new Exception(StringUtil.format("文件 {} 没有读取权限", path));
        }
        
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,!cover),"UTF-8"));
            
            writer.write(fileContent);
        } catch (IOException e) {
            logger.error(StringUtil.format("文件 {} 写入内容失败,{}", path,e.getMessage()));
            throw e;
        } finally {
            if (writer != null) {
                try {
                    writer.flush();
                    writer.close();
                } catch (IOException e1) {
                }
            }
        }
    }
    
    /**路径是否存在
     * @param path
     * @return
     * @throws Exception
     */
    public static boolean fileExists(String path,boolean dir) throws Exception{
        File file=new File(path);
        if(!file.exists()){
            return false;
        }
        if(dir){
            if(!file.isDirectory()){
                throw new Exception(StringUtil.format("路径 {} 不是文件夹", path));
            }
        }else{
            if(!file.isFile()){
                throw new Exception(StringUtil.format("路径 {} 不是文件", path));
            }
        }
        return true;
    }
    
}

相关文章
|
Android开发 架构师
Android:动态更换桌面ICON
前言 当老板和产品提出这种需求的时候,我并不感到害怕,心里甚至有点窃喜,因为大厂基本都有这种效果,那肯定也好实现。当我一查资料的时候,发现情况不容乐观。
4364 0
|
8月前
|
机器学习/深度学习 人工智能 异构计算
SkyReels-A1:解放动画师!昆仑开源「数字人制造机」:一张照片生成逼真虚拟主播,表情连眉毛颤动都可控
SkyReels-A1 是昆仑万维开源的首个 SOTA 级别表情动作可控的数字人生成模型,支持高保真肖像动画生成和精确的表情动作控制。
643 23
|
8月前
|
数据管理 Linux iOS开发
Splunk Enterprise 9.4.1 (macOS, Linux, Windows) 发布 - 机器数据管理和分析
Splunk Enterprise 9.4.1 (macOS, Linux, Windows) 发布 - 机器数据管理和分析
141 0
Splunk Enterprise 9.4.1 (macOS, Linux, Windows) 发布 - 机器数据管理和分析
|
Linux
Linux——服务器时间不同步
Linux——服务器时间不同步
160 0
|
12月前
|
数据安全/隐私保护 Python
Python中的MD5加密“解密”
Python中的MD5加密“解密”
311 0
|
敏捷开发 存储 数据管理
自动化测试框架设计:从理论到实践
【7月更文挑战第13天】本文将深入探讨自动化测试框架的设计原理与实现方法。通过分析自动化测试的必要性和框架设计的基本原则,结合具体案例,展示如何从零开始构建一个高效、可维护的自动化测试系统。文章不仅涵盖框架的结构设计,还包括最佳实践和常见问题的解决策略,为读者提供一套完整的解决方案和实操指南。
|
Oracle Ubuntu Java
cannot execute binary jdk问题
【7月更文挑战第15天】
787 5
|
人工智能 大数据 云计算
软件即服务(SaaS)的兴起:技术变革引领商业新纪元
【6月更文挑战第21天】SaaS兴起引领商业变革: 互联网与云计算催生了SaaS模式,降低企业IT成本,提供按需订阅、免安装维护的软件服务。多租户架构保证数据安全,实时更新促进效率与创新。SaaS重塑商业模式,降低创业门槛,助力企业灵活应对市场变化,驱动数字化转型和行业发展。未来,SaaS将继续扮演创新推手角色。
|
Java Spring Maven
gradle 配置指南
在`build.gradle`中配置Gradle仓库,首先添加阿里云公共仓库
|
Linux 网络安全
配置Linux服务器时间同步
配置Linux服务器时间同步
配置Linux服务器时间同步