java使用nio2拷贝文件的示例
作者:
这个程序只是为了更方便的进行拷贝文件(夹)而创造。
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);
}
}