這個程序只是為了更方便的進行拷貝文件(夾)而創造。
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);
}
}