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