java使用nio2拷贝文件的示例

时间:2021-07-09 21:01:35

这个程序只是为了更方便的进行拷贝文件(夹)而创造。
1.可以不用新建文件夹,就像windows的复制粘贴一样简单。
2.有简单的出错重连机制
3.不需要重复拷贝,差异化复制文件。
4.拷贝文件夹的时候可以不用复制全路径,只关注需要拷贝的文件夹。
5.程序做了简单的必要检查,效率也不算低。
6.使用的是7的nio2的新API。

 

复制代码代码如下:


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.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.Stack;

 

import org.apache.log4j.Logger;

import com.xyq.myfile.cope.entity.PathType;
import com.xyq.util.MD5Util;

/***
 * 基于jdk7的拷贝算法
 * 
 * @author xyq
 * 
 */
public class MyFiles2 {

 private String src;
 private String tar;
 private Path srcPath;
 private Path tarPath;
 private int reCount = 3;
 private boolean isCover = false;
 private boolean useMd5 = false;
 private int subNameNum = 0;
 // log4j对象
 private Logger logger;
 // 在文件夹-->文件夹模式中,是否拷贝全路径,默认不拷贝
 private boolean isCopeAllPath = false;

 public MyFiles2(String src, String tar) {

  this.src = src;
  this.tar = tar;
  this.srcPath = Paths.get(src);
  this.tarPath = Paths.get(tar);
 }

 public MyFiles2() {
 }

 public String getSrc() {
  return src;
 }

 public void setSrc(String src) {
  this.src = src;
  this.srcPath = Paths.get(src);
 }

 public String getTar() {
  return tar;
 }

 public void setTar(String tar) {
  this.tar = tar;
  this.tarPath = Paths.get(tar);
 }

 public int getReCount() {
  return reCount;
 }

 public void setReCount(int reCount) {
  this.reCount = reCount;
 }

 public boolean isCover() {
  return isCover;
 }

 public void setCover(boolean isCover) {
  this.isCover = isCover;
 }

 public Logger getLogger() {
  return logger;
 }

 public void setLogger(Logger logger) {
  this.logger = logger;
 }

 public boolean isUseMd5() {
  return useMd5;
 }

 public void setUseMd5(boolean useMd5) {
  this.useMd5 = useMd5;
 }

 public boolean isCopeAllPath() {
  return isCopeAllPath;
 }

 public void setCopeAllPath(boolean isCopeAllPath) {
  this.isCopeAllPath = isCopeAllPath;
 }

 public boolean copeFileCore(PathType... types) {

  if (initCheck() && initCheck2s(this.srcPath, false))
   return copeFileCore(this.srcPath, this.tarPath, reCount, isCover,
     types);
  return false;
 }

 private boolean initCheck() {

  if (this.srcPath == null) {
   logInfo("原始路径未设置,程序无法启动~~");
   return false;
  } else if (this.tarPath == null) {
   logInfo("目标路径未设置,程序无法启动~~");
   return false;
  } else if (!Files.exists(srcPath)) {
   logInfo("原始路径不存在,程序无法启动~~");
   return false;
  } else if (!Files.exists(tarPath.getRoot())) {
   logInfo("目标路径的根盘符不存在,程序无法启动~~");
   return false;
  }
  return true;
 }

 private boolean initCheck2s(Path path, boolean dOrF) {

  if (!Files.isDirectory(path)) {
   if (dOrF) {
    logInfo(path + "不是一个有效的文件夹");
    return false;
   }
  } else if (!dOrF) {
   logInfo(path + "不是一个有效的文件");
   return false;
  }
  return true;
 }

 /****
  * 拷贝文件算法
  * 
  * @param path1
  *            原始路径
  * @param path2
  *            目标路径
  * @param reCount
  *            重复次数
  * @param isCover
  *            是否覆盖拷贝
  * @param types
  *            你所写的目标路径是文件还是文件夹,可以不写,默认是文件
  * @return
  */
 public boolean copeFileCore(Path path1, Path path2, int reCount,
   boolean isCover, PathType... types) {

  // 如果原始文件不存在,就直接异常
  if (!initCheck() || !initCheck2s(path1, false))
   return false;
  PathType type = PathType.FILES;
  if (types != null && types.length > 0) {
   type = types[0];
   // 如果目标是一个文件夹,并且指定是往一个文件夹拷贝的时候
   if (type.equals(PathType.DIRS)) {
    path2 = Paths.get(path2.toString(), path1.getFileName()
      .toString());
   }
  }
  // 如果目标文件已经存在,就判断是否相同,相同就不用拷贝了
  if (Files.exists(path2)) {
   if (Files.isDirectory(path2) && PathType.FILES.equals(type)) {
    logInfo(path2 + "已经存在,它是一个文件夹而不是文件");
    return false;
   }
   if (isSameFile(path1, path2, useMd5))
    return true;
  }
  // 当目标文件不存在的时候
  else {
   Path parPath = path2.getParent();
   // 如果目标文件的父类文件夹不存在,就尝试创建
   if (!Files.exists(parPath))
    for (int i = 1; i < reCount; i++) {
     try {
      Files.createDirectories(parPath);
      break;
     } catch (Exception e) {
      if (i == reCount) {
       logInfo(e);
       return false;
      }
     }
    }
  }

  for (int i = 1; i <= reCount; i++) {
   try {
    if (isCover)
     Files.copy(path1, path2,
       StandardCopyOption.REPLACE_EXISTING,
       StandardCopyOption.COPY_ATTRIBUTES);
    else
     Files.copy(path1, path2, StandardCopyOption.COPY_ATTRIBUTES);
    // 同步最后修改时间
    synLastFileTime(path1, path2);
    break;
   } catch (IOException e) {
    // 如果在指定时间内都无法完成拷贝,那么就果断记录到异常信息中
    if (i == reCount) {
     logInfo(e);
     return false;
    }
   }
  }
  return true;

 }

 public void copeDir() {

  if (!initCheck() || !initCheck2s(srcPath, true))
   return;
  copeDir(this.srcPath.toString(), this.tarPath.toString());
 }

 /***
  * 拷贝文件夹保护层
  * 
  * @param path1
  * @param path2
  */
 public void copeDir(String path1, final String path2) {

  if (!initCheck() || !initCheck2s(srcPath, true))
   return;
  Path p1 = Paths.get(path1);
  final Path tarPath = Paths.get(path2);
  if (!isCopeAllPath)
   subNameNum = srcPath.getNameCount() - 1;
  try {
   Files.walkFileTree(p1, new FileVisitor<Path>() {

    Path p2 = null;
    Stack<Path> dirStack = new Stack<Path>();

    @Override
    public FileVisitResult preVisitDirectory(Path dir,
      BasicFileAttributes attrs) throws IOException {

     // 当使用不拷贝全路径时,作为本文件夹的名字节点的记录位置
     // if (!copeAllPath)
     /****
      * 如果是相同的文件夹,那么就跳过无需拷贝.
      */
     if (isSamePath(dir, tarPath)) {
      System.out.println("是相同的,跳过!!!!!!!!!!!!!!!!!");
      return FileVisitResult.SKIP_SUBTREE;
     }
     p2 = replacePath(dir, path2, subNameNum);
     if (dir.toFile().length() == 0 && !Files.exists(p2))
      Files.createDirectories(p2);
     dirStack.push(p2);
     return FileVisitResult.CONTINUE;

    }

    @Override
    public FileVisitResult visitFile(Path file,
      BasicFileAttributes attrs) throws IOException {

     Path toFilePath = Paths.get(dirStack.peek().toString(),
       file.getFileName().toString());
     copeFileCore(file, toFilePath, 3, true);
     return FileVisitResult.CONTINUE;

    }

    @Override
    public FileVisitResult visitFileFailed(Path file,
      IOException exc) throws IOException {

     return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir,
      IOException exc) throws IOException {
     if (!dirStack.isEmpty())
      dirStack.pop();
     return FileVisitResult.CONTINUE;
    }

   });
  } catch (IOException e) {
   logInfo(e);
  }
 }

 /***
  * 替换Path
  * 
  * @param path1
  * @param path2
  * @return
  */
 private Path replacePath(Path path1, String path2, int nameCountNum) {

  if (path1.getNameCount() == 0 && path1.equals(path1.getRoot()))
   return Paths.get(path2);
  return Paths.get(path2,
    path1.subpath(nameCountNum, path1.getNameCount()).toString());
 }

 /***
  * 要么是地址完全相同,要么就是原始文件的父类与目标相同,因为程序支持拷贝到父类
  * 
  * @param path1
  * @param path2
  * @return
  */
 private boolean isSamePath(Path path1, Path path2) {

  if (path1.equals(path2))
   return true;
  return false;
 }

 /***
  * 同步文件的修改时间
  * 
  * @param path1
  * @param path2
  * @return
  */
 public boolean synLastFileTime(Path path1, Path path2) {

  FileTime srcPathTime;
  try {
   srcPathTime = Files.getLastModifiedTime(path1);
   Files.setLastModifiedTime(path2, srcPathTime);
   return srcPathTime.equals(Files.getLastModifiedTime(path2));
  } catch (IOException e) {
   logInfo(e);
   return false;
  }
 }

 /***
  * 判断两个文件是否相同
  * 
  * @param path1
  * @param path2
  * @return
  */
 public boolean isSameFile(Path path1, Path path2, boolean useMd5) {

  try {
   // 只要两个文件长度不一致,就绝对不是一个文件
   if (Files.size(path1) != Files.size(path2))
    return false;
   // 如果是最后的修改时间不一样,就直接使用MD5验证
   else if (!Files.getLastModifiedTime(path1).equals(
     Files.getLastModifiedTime(path2))
     || useMd5)
    return MD5Util.getFileMD5String(path1.toFile()).equals(
      MD5Util.getFileMD5String(path2.toFile()));
   return true;
  } catch (Exception e) {
   logInfo(e);
   return false;
  }
 }

 /***
  * 针对异常处理的
  */
 private void logInfo(Exception e) {

  if (this.logger != null)
   logger.error(e.getMessage());
  else if (e != null)
   System.out.println("异常:" + e.getMessage());
 }

 private void logInfo(String errorMessage) {

  if (this.logger != null)
   logger.error(errorMessage);
  else
   System.out.println("异常:" + errorMessage);
 }

 public static void main(String[] args) {

  // new MyFiles2("e:/t/1.txt", "e:/3/33").copeFileCore();
  MyFiles2 my = new MyFiles2("e:/ttt/tt/t/1.txt", "e:/3/33.txt");
  my.copeFileCore(PathType.DIRS);
 }
}

 

 

复制代码代码如下:


public enum PathType {

 

 FILES,DIRS;
}

 

 

复制代码代码如下:


import java.io.Closeable;

 

public class CloseIoUtil {

 /***
  * 关闭IO流
  * 
  * @param cls
  */
 public static void closeAll(Closeable... cls) {

  if (cls != null) {
   for (Closeable cl : cls) {
    try {
     if (cl != null)
      cl.close();
    } catch (Exception e) {

    } finally {
     cl = null;
    }
   }
  }
 }
}

 

 

复制代码代码如下:


import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

 

public class MD5Util {

 protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6',
   '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 protected static MessageDigest messagedigest = null;
 static {
  try {
   messagedigest = MessageDigest.getInstance("MD5");
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
 }

 public static String getFileMD5String(File file) throws IOException {

  /***
   * MappedByteBuffer是NIO的API,使用这个API会有一个bug,
   * 当使用 FileChannel.map 方法时,MappedByteBuffer 已经在系统内占用了一个句柄,
   * 而使用 FileChannel.close 方法是无法释放这个句柄的,、
   * 且FileChannel有没有提供类似 unmap 的方法,因此会出现无法删除文件的情况。
   */
  // FileInputStream in = new FileInputStream(file);
  // FileChannel ch = in.getChannel();
  // MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY,
  // 0,
  // file.length());

  InputStream fis = null;
  BufferedInputStream bis = null;
        fis = new FileInputStream(file);  
        bis = new BufferedInputStream(fis);
        byte[] buffer = new byte[2048];  
        int numRead = 0;  
        while ((numRead = bis.read(buffer)) > 0) {  
            messagedigest.update(buffer, 0, numRead);  
        }  
        CloseIoUtil.closeAll(bis,fis);
        return bufferToHex(messagedigest.digest());  
 }

 public static String getMD5String(String s) {
  return getMD5String(s.getBytes());
 }

 public static String getMD5String(byte[] bytes) {
  messagedigest.update(bytes);
  return bufferToHex(messagedigest.digest());
 }

 private static String bufferToHex(byte bytes[]) {
  return bufferToHex(bytes, 0, bytes.length);
 }

 private static String bufferToHex(byte bytes[], int m, int n) {
  StringBuffer stringbuffer = new StringBuffer(2 * n);
  int k = m + n;
  for (int l = m; l < k; l++) {
   appendHexPair(bytes[l], stringbuffer);
  }
  return stringbuffer.toString();
 }

 private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
  char c0 = hexDigits[(bt & 0xf0) >> 4];
  char c1 = hexDigits[bt & 0xf];
  stringbuffer.append(c0);
  stringbuffer.append(c1);
 }

 public static boolean checkPassword(String password, String md5PwdStr) {
  String s = getMD5String(password);
  return s.equals(md5PwdStr);
 }

 public static void main(String[] args) throws IOException {

  File big = new File("e:/sss.txt");
  String md5 = getFileMD5String(big);
  //
  // long end = System.currentTimeMillis();
  // System.out.println("md5:" + md5);
  // System.out.println("time:" + ((end - begin) / 1000) + "s");

  System.out.println(md5);

 }

}

 

 

复制代码代码如下:


import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

 

public class MD5Util {

 protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6',
   '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 protected static MessageDigest messagedigest = null;
 static {
  try {
   messagedigest = MessageDigest.getInstance("MD5");
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
 }

 public static String getFileMD5String(File file) throws IOException {

  /***
   * MappedByteBuffer是NIO的API,使用这个API会有一个bug,
   * 当使用 FileChannel.map 方法时,MappedByteBuffer 已经在系统内占用了一个句柄,
   * 而使用 FileChannel.close 方法是无法释放这个句柄的,、
   * 且FileChannel有没有提供类似 unmap 的方法,因此会出现无法删除文件的情况。
   */
  // FileInputStream in = new FileInputStream(file);
  // FileChannel ch = in.getChannel();
  // MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY,
  // 0,
  // file.length());

  InputStream fis = null;
  BufferedInputStream bis = null;
        fis = new FileInputStream(file);  
        bis = new BufferedInputStream(fis);
        byte[] buffer = new byte[2048];  
        int numRead = 0;  
        while ((numRead = bis.read(buffer)) > 0) {  
            messagedigest.update(buffer, 0, numRead);  
        }  
        CloseIoUtil.closeAll(bis,fis);
        return bufferToHex(messagedigest.digest());  
 }

 public static String getMD5String(String s) {
  return getMD5String(s.getBytes());
 }

 public static String getMD5String(byte[] bytes) {
  messagedigest.update(bytes);
  return bufferToHex(messagedigest.digest());
 }

 private static String bufferToHex(byte bytes[]) {
  return bufferToHex(bytes, 0, bytes.length);
 }

 private static String bufferToHex(byte bytes[], int m, int n) {
  StringBuffer stringbuffer = new StringBuffer(2 * n);
  int k = m + n;
  for (int l = m; l < k; l++) {
   appendHexPair(bytes[l], stringbuffer);
  }
  return stringbuffer.toString();
 }

 private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
  char c0 = hexDigits[(bt & 0xf0) >> 4];
  char c1 = hexDigits[bt & 0xf];
  stringbuffer.append(c0);
  stringbuffer.append(c1);
 }

 public static boolean checkPassword(String password, String md5PwdStr) {
  String s = getMD5String(password);
  return s.equals(md5PwdStr);
 }

 public static void main(String[] args) throws IOException {

  File big = new File("e:/sss.txt");
  String md5 = getFileMD5String(big);
  //
  // long end = System.currentTimeMillis();
  // System.out.println("md5:" + md5);
  // System.out.println("time:" + ((end - begin) / 1000) + "s");

  System.out.println(md5);

 }
}