package com.xyq.io.simply.core;
import java.io.File;
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.util.ArrayList;
import java.util.List;
import com.xyq.io.enums.FileTypeMode;
import com.xyq.io.enums.OptionFile_TYPE;
import com.xyq.io.inf.NewNIoInf;
import com.xyq.io.util.FindFileUtil;
import com.xyq.io.util.MD5Util;
public class NewNIO implements NewNIoInf {
/***
* 拷貝或者移動文件
*/
@Override
public boolean copeOrMoveFile(String src, String tar, OptionFile_TYPE type) {
return realCopeOrMoveFile(Paths.get(src), tar, type);
}
private boolean realCopeOrMoveFile(Path srcPath, String tar,
OptionFile_TYPE type) {
Path tarPath = null;
boolean copeSuccess = true;
// 必須原始文件存在
if (srcPath.toFile().exists()) {
/***
* 如果原始路徑是帶斜杠的那么就認為這是一個文件夾
*/
if (isDir(tar))
tarPath = Paths.get(tar + File.separator
+ srcPath.toFile().getName());
else
tarPath = Paths.get(tar);
/***
* 然后進行N次(可以作為參數)拷貝操作(出錯重連),是否覆蓋拷貝,拷貝屬性,拷貝操作不能使用回滾選項
*/
for (int i = 0; i < 3; i++) {
/***
* 如果是目標文件已經存在
*/
if (tarPath.toFile().exists()) {
/***
* 如果驗證兩個文件夾是相同的,拷貝選項下就不用拷貝,移動選項下就是刪除原始文件
*/
// 拷貝
if (OptionFile_TYPE.COPE.equals(type)) {
if (equalsFile(srcPath.toFile(), tarPath.toFile()))
return true;
else
copeSuccess = copeFile(srcPath, tarPath, true);
}
/***
* 移動操作,這里得非常小心,正常情況下,如果兩個文件是一樣的話,
* 那么直接刪除原始文件就可以了。但是,如果兩個文件的一樣,并且地址也
* 是一樣的話,那么就不能刪除原始的了,因為就是同一個文件,不能刪除的。
*/
else if (OptionFile_TYPE.MOVE.equals(type)) {
if (equalsFile(srcPath.toFile(), tarPath.toFile())) {
if (!srcPath.toFile().getAbsoluteFile()
.equals(tarPath.toFile().getAbsoluteFile()))
try {
Files.delete(srcPath);
/***
* 之所以要手動指向true,是因為可能存在前面刪除失敗的情況
*/
if (!copeSuccess)
copeSuccess = true;
} catch (IOException e) {
copeSuccess = false;
}
// 前面因為有異常的可能就不直接return,這里就可以了
else
return true;
} else
copeSuccess = moveFile(srcPath, tarPath);
}
}
/***
* 當目標文件不存在的時候,先判斷父類文件夾是可創 建(父類文件夾存在或者可以創建),可創建時就創建
*/
else {
File par = tarPath.getParent().toFile();
/***
* 如果父類文件夾不存在并且無法創建,那么就不用拷貝了
*/
if (!par.exists() && !par.mkdirs())
copeSuccess = false;
else if (OptionFile_TYPE.COPE.equals(type))
copeSuccess = copeFile(srcPath, tarPath, false);
else if (OptionFile_TYPE.MOVE.equals(type))
copeSuccess = moveFile(srcPath, tarPath);
}
// 如果操作成功,跳出循環
if (copeSuccess)
break;
}
} else
copeSuccess = false;
return copeSuccess;
}
/****
* 拷貝文件
*/
private boolean copeFile(Path srcPath, Path tarPath, boolean isExist) {
if (isExist)
try {
Files.copy(srcPath, tarPath,
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException e) {
return false;
}
else
try {
Files.copy(srcPath, tarPath, StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException e) {
return false;
}
return true;
}
/***
* 移動文件,不能使用屬性選項
*
* @param srcPath
* @param tarPath
* @return
*/
private boolean moveFile(Path srcPath, Path tarPath) {
try {
Files.move(srcPath, tarPath, StandardCopyOption.ATOMIC_MOVE);
} catch (IOException e) {
return false;
}
return true;
}
/***
* 判斷path路徑是否是一個文件夾
*
* @param path
* @return
*/
private boolean isDir(String path) {
char lastC = path.charAt(path.length() - 1);
if (lastC == '\\' || lastC == '/')
return true;
return false;
}
/***
* 這是來驗證兩個文件是否相同,只是簡單驗證,可以強制必須使用md5進行驗證
*/
public boolean equalsFile(File src, File tar) {
// 如果兩個文件的長度不一樣,那么肯定兩個文件是不一樣的
if (src.length() != tar.length())
return false;
if (!src.getName().equals(tar.getName())
|| src.lastModified() != tar.lastModified())
return MD5Util.EncoderFileByMd5(src).equals(
MD5Util.EncoderFileByMd5(tar));
return true;
}
/***
* 拷貝或者移動文件夾
*/
@Override
public void copeOrMoveDirectory(String src, final String tar, int tierSize,
final OptionFile_TYPE type) {
if (!new File(src).exists())
throw new RuntimeException("找不到原始文件夾" + src);
final int rootPos = getRootPosition(new File(src), tierSize);
if (rootPos != -1) {
try {
Files.walkFileTree(Paths.get(src), new FileVisitor<Path>() {
String tarDirString = null;
/***
* 到達文件夾前,先把目標路徑寫好
*
* @param dir
* @param attrs
* @return
* @throws IOException
*/
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
tarDirString = dir.toFile().getAbsolutePath();
tarDirString = tar + tarDirString.substring(rootPos)
+ File.separator;
return FileVisitResult.CONTINUE;
}
/***
* 到達文件之后,進行拷貝或者移動操作
*
* @param file
* @param attrs
* @return
* @throws IOException
*/
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
File f = file.toFile();
if (f.exists() && f.canRead() && !f.isHidden())
realCopeOrMoveFile(file, tarDirString, type);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
/***
* 到達文件夾后
*
* @param dir
* @param exc
* @return
* @throws IOException
*/
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
} catch (Exception e) {
e.printStackTrace();
}
// 如果是剪切操作,并且剪切成功,那么就要刪除所有文件夾
if (OptionFile_TYPE.MOVE.equals(type) && isBlockDir(src))
delDir(src);
} else
throw new RuntimeException("指定父類文件夾層次錯誤~~~");
}
/***
* 根據指定層次獲取指定盤符的位置
*/
private int getRootPosition(File file, int tier) {
if (file != null) {
String path = file.getAbsolutePath();
int cc = 0;
for (int i = path.length() - 1; i >= 0; i--) {
if (path.charAt(i) == '\\') {
cc++;
if (cc == tier + 1) {
cc = i;
return cc;
}
}
}
}
return -1;
}
/***
* 查看該文件夾下是否還有文件
*
* @param dirPath
* @return
*/
private boolean isBlockDir(String dirPath) {
File dir = new File(dirPath);
File[] dirList = dir.listFiles();
if (dirList == null || dirList.length == 0)
return true;
else {
// 尋找文件
for (File f : dirList)
if (!f.isDirectory())
return false;
}
return true;
}
/***
* 刪除空文件夾
*
* @param dirPath
*/
private void delDir(String dirPath) {
File dir = new File(dirPath);
File[] dirList = dir.listFiles();
if (dirList == null || dirList.length == 0)
dir.delete();
else {
// 刪除所有文件
for (File f : dirList)
if (f.isDirectory())
delDir(f.getAbsolutePath());
else
f.delete();
// 刪除完當前文件夾下所有文件后刪除文件夾
dirList = dir.listFiles();
if (dirList.length == 0)
dir.delete();
}
}
/***
* 根據文件類型查找相關的文件
*/
@Override
public List<String> findFilesByType(String dir, String[] keys,
boolean isMatchCase) throws IOException {
List<String> list = new ArrayList<String>();
Files.walkFileTree(Paths.get(dir), new FindFileUtil(keys, isMatchCase,
list, FileTypeMode.TYPES));
return list;
}
/***
* 根據文件名稱查找相關的文件
*/
@Override
public List<String> findFilesByName(String dir, String[] keys,
boolean isMatchCase) throws IOException {
List<String> list = new ArrayList<String>();
Files.walkFileTree(Paths.get(dir), new FindFileUtil(keys, isMatchCase,
list, FileTypeMode.NAMES));
return list;
}
public static void main(String[] args) throws IOException {
NewNIoInf inf = new NewNIO();
inf.copeOrMoveFile("e:/cc/dd/11.txt", "e:/XX/xxx/zzz/",
OptionFile_TYPE.COPE);
inf.copeOrMoveDirectory("e:\\BB\\CC\\DD", "e:\\",1, OptionFile_TYPE.MOVE);
System.out.println(inf.findFilesByName("D:\\workspace", new String[] { "txt" },
false).size());
}
}
---------------------------
package com.xyq.io.enums;
/***
* 文件類型
* @author xyq
*
*/
public enum FileTypeMode {
TYPES,NAMES
}
---------------------------------
package com.xyq.io.enums;
/***
* 操作文件的類型
* @author xyq
*
*/
public enum OptionFile_TYPE {
COPE,MOVE;
}
---------------------
package com.xyq.io.inf;
import java.io.IOException;
import java.util.List;
import com.xyq.io.enums.OptionFile_TYPE;
public interface NewNIoInf {
/***
* 拷貝或者移動文件
* @param src
* @param tar
* @return
*/
public boolean copeOrMoveFile(String src,String tar,OptionFile_TYPE type);
/***
* 拷貝或者移動文件夾
* @param src
* @param tar
* @param tierSize 層次,拷貝完成后的路徑0只是當前文件夾,+1就是加一級父類文件夾(但不拷貝父類內容)
* @param type
*/
public void copeOrMoveDirectory(String src,String tar,int tierSize,OptionFile_TYPE type);
/**
* 根據文件類型查找相關文件集合,多種類型時用逗號隔開
*
* @param dir
* 目錄
* @param keys
* 文件類型
* @param isMatchCase
* 是否區分大小寫
* @return
* @throws IOException
*/
List<String> findFilesByType(String dir, String[] keys, boolean isMatchCase)
throws IOException;
/**
* 根據文件名稱查找相關文件集合,多種民稱時用逗號隔開
*
* @param dir
* 目錄
* @param keys
* 文件名稱
* @param isMatchCase
* 是否區分大小寫
* @return
* @throws IOException
*/
List<String> findFilesByName(String dir, String[] keys, boolean isMatchCase)
throws IOException;
}
--------------------
package com.xyq.io.util;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import com.xyq.io.enums.FileTypeMode;
public class FindFileUtil extends SimpleFileVisitor<Path> {
/***
* 關鍵詞列表,是否轉換大小寫,返回結果集
*/
private String[] keyArray = null;
private boolean isMatchCase;
private List<String> resultList;
private FileTypeMode mode;
public FindFileUtil(String[] keyArray, boolean isMatchCase,
List<String> resultList, FileTypeMode mode) {
this.keyArray = keyArray;
this.isMatchCase = isMatchCase;
this.resultList = resultList;
this.mode = mode;
}
@SuppressWarnings("unused")
private FindFileUtil() {
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
File f = file.toFile();
if (f.exists() && f.canRead() && !f.isHidden())
if (this.keyArray != null) {
for (String key : this.keyArray) {
if (!this.isMatchCase)
key = key.toLowerCase();
if (matchFile(file, this.mode, key, isMatchCase))
resultList.add(file.toString());
}
}
return FileVisitResult.CONTINUE;
}
/***
* 根據大小寫和類型或名稱進行文件匹配
*
* @param file
* @param mode
* @param key
* @param isMatchCase
* @return
*/
private boolean matchFile(Path file, FileTypeMode mode, String key,
boolean isMatchCase) {
File f = file.toFile();
if (f.exists() && f.canRead() && !f.isHidden()
&& !"System Volume Information".equals(f.getName())) {
String fileName = null;
if (FileTypeMode.TYPES.equals(mode)) {
fileName = file.toString();
return isMatchCase ? fileName.endsWith(key) : fileName
.toLowerCase().endsWith(key);
} else if (FileTypeMode.NAMES.equals(mode)) {
fileName = file.toFile().getName();
return isMatchCase ? (fileName.indexOf(key) == -1 ? false
: true)
: (fileName.toLowerCase().indexOf(key) == -1 ? false
: true);
}
}
return false;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc)
throws IOException {
//如果錯誤信息中包含X:\System Volume Information,這是表示系統的隱藏盤,是不能讀的
System.out.println(exc.getMessage());
return FileVisitResult.CONTINUE;
}
}
--------------------------
package com.xyq.io.util;
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;
}
}
}
}
}
-----------------------------
package com.xyq.io.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Encoder;
public class MD5Util {
/***
* 加密字符串
*
* @param str
* @return
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String EncoderStringByMd5(String str)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
// 確定計算方法
MessageDigest md5 = MessageDigest.getInstance("MD5");
BASE64Encoder base64en = new BASE64Encoder();
// 加密后的字符串
String newstr = base64en.encode(md5.digest(str.getBytes("utf-8")));
return newstr;
}
/***
* 加密文件
*
* @param file
* @return
* @throws NoSuchAlgorithmException
* @throws IOException
*/
public static String EncoderFileByMd5(File file) {
String newstr = null;
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
// 確定計算方法
MessageDigest md5 = MessageDigest.getInstance("MD5");
BASE64Encoder base64en = new BASE64Encoder();
byte[] buffer = new byte[1024];
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
int length = -1;
while ((length = bis.read(buffer)) != -1)
md5.update(buffer, 0, length);
// 加密后的字符串
newstr = base64en.encode(md5.digest());
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseIoUtil.closeAll(bis, fis);
}
return newstr;
}
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
System.out.println(EncoderStringByMd5("23"));
}
}