檔案 File 常見操作 工具
阿新 • • 發佈:2018-11-25
Markdown版本筆記 | 我的GitHub首頁 | 我的部落格 | 我的微信 | 我的郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | [email protected] |
檔案 File 常見操作 工具
目錄
目錄檔案基本操作
建立檔案或目錄
重新命名
建立多級目錄
建立帶目錄的檔案
刪除多級目錄
獲取目錄下的檔案列表
其他常見操作
常用封裝的工具
遞迴遍歷目錄下的檔案
遞迴刪除目錄下的檔案
生成格式良好的檔案目錄
效果演示
程式碼
配置 Config
格式化檔案大小
檔案複製的幾種方式
速度比較
copyFileByBuffer
copyFileByByteArray
copyFileByByteArray2
copyFileByByte
copyFileByByteOnce
copyFileByBufLine
copyFileByCharArray
copyFileByChar
檔案基本操作
建立檔案或目錄
private static void testCreate() { File file = new File("d:/不存在的檔案.txt");//注意,這一步並沒有在磁碟建立檔案,只是封裝了一個物件 System.out.println("不存在的檔案:" + (file.exists() || file.isFile() || file.isDirectory()));//【false】檔案不存在時既不是 isFile 也不是 isDirectory try { System.out.println(file.createNewFile());//【true】這一步是在磁碟中建立檔案 System.out.println(file.exists() + "--" + file.isFile() + "--" + file.isDirectory());//【true--true--false】 System.out.println(file.createNewFile() || file.mkdirs());//【false】如果檔案已存在,則不建立 } catch (IOException e) { e.printStackTrace(); } File dir = new File("d:/不存在的目錄"); System.out.println("不存在的目錄:" + (dir.exists() || dir.isFile() || dir.isDirectory()));//【false】 System.out.println(dir.mkdirs());//【true】建立目錄 System.out.println(dir.exists() + "--" + dir.isFile() + "--" + dir.isDirectory());//【true--false--true】 try { System.out.println(dir.mkdirs() || dir.createNewFile());//【false】如果目錄已存在,則不建立 } catch (IOException e) { e.printStackTrace(); } }
重新命名
private static void testRename() {
File dir = new File("d:/目錄");
System.out.println("原目錄下的檔案列表:" + Arrays.toString(dir.list())); //[檔案.txt]
File renameDir = new File(dir.getParent(), "重新命名目錄");
//return true if and only if the renaming succeeded; false otherwise
boolean succee = dir.renameTo(renameDir);//重新命名時須指定重新命名後存放的路徑,否則會移動到預設路徑
System.out.println("重新命名是否成功:" + succee + ",原目錄是否還存在:" + dir.exists()); //【true,false】
System.out.println("新目錄下的檔案列表:" + Arrays.toString(renameDir.list())); //[檔案.txt]
}
建立多級目錄
private static void testCreateDir() {
File dir1 = new File("d:/a/aa/1");
File dir2 = new File("d:/a/aa");
File dir3 = new File("d:/a/");
//mkdir 只建立最後一級目錄,若父目錄不存在則建立失敗(但不報異常);mkdirs 可以同時建立多級目錄;建立新目錄時不會刪除舊目錄
//return true if and only if the directory was created, along with all necessary parent directories最後一級目錄建立成功則返回true
System.out.println(dir1.mkdir() || dir2.mkdir() || dir1.exists() || dir2.exists() || dir2.exists());//【false】
System.out.println(dir1.mkdirs() && dir1.exists() && dir2.exists() && dir3.exists());//【true】
System.out.println(dir1.mkdirs() || dir1.mkdir() || dir2.mkdirs() || dir2.mkdir() || dir3.mkdirs() || dir3.mkdir());//【false】
}
建立帶目錄的檔案
private static void testCreateFileWithDir() {
boolean success;
try {
//return true if the named file does not exist and was successfully created; false if the named file already exists
success = new File("d:/aaa/aaa.txt").createNewFile();//目錄不存在時呼叫 createNewFile 方法會報異常
System.out.println("建立檔案是否成功:" + success);
} catch (IOException e) {
e.printStackTrace();
System.out.println("建立檔案出現異常,往往是因為父目錄不存在");
}
//建立帶目錄的檔案的標準姿勢
File file = new File("d:/aaa/aaa.txt");
if (!file.getParentFile().exists()) {
success = file.getParentFile().mkdirs();//如果父目錄不存在則先建立父目錄
System.out.println("父目錄是否建立成功:" + success);
}
try {
System.out.println("建立檔案是否成功:" + file.createNewFile());
} catch (IOException e) {
e.printStackTrace();
System.out.println("建立檔案出現異常,往往是因為父目錄不存在");
}
}
刪除多級目錄
private static void testDelDir() {
File dir1 = new File("d:/b/刪除/1");
File dir2 = new File("d:/b/刪除");
File dir3 = new File("d:/b");
System.out.println(dir1.mkdirs() && dir1.exists() && dir2.exists() && dir3.exists());//【true】
//如果有目錄下有內容(不管是目錄還是檔案),則不能此目錄不能被刪除
System.out.println(dir3.delete() + "--" + dir2.delete() + "--" + dir3.delete());//【false--false--false】
//如果目錄中無內容,則可以刪除此目錄(僅僅是刪掉最裡層的那一個目錄),所以檔案(isFile()為true)是可以直接刪除的
System.out.println(dir1.delete() + "--" + dir2.delete() + "--" + dir3.delete());//【true--true--true】
System.out.println(dir1.exists() || dir2.exists() || dir3.exists());//【false】
}
獲取目錄下的檔案列表
private static void testList() {
File[] rootDirs = File.listRoots();
System.out.println("獲取系統根目錄的檔案列表(磁碟列表)\n" + Arrays.toString(rootDirs));//[C:\, D:\]
File file = new File("d:/一個不存在的目錄");
//如果 file 不是一個目錄,包括:①是一個檔案 ②既不是檔案也不是目錄(即 file 不存在),則所有相關的 list 操作都返回 null
//如果 file 是一個目錄(是一個目錄的必要條件為:此目錄一定是在磁碟中存在的)但目錄下面沒有任何檔案,則返回一個長度為 0 的陣列
//注意,所有 list 操作獲取的列表中,都包含此目錄下的所有檔案以及資料夾(包含隱藏檔案),但不包括資料夾下面的子目錄(不遞迴)
System.out.println("\n必須保證是一個目錄\n" + (!file.isDirectory() && file.list() == null && file.listFiles() == null));//【true】
file = new File("d:/");
System.out.println("\n獲取【檔名稱】列表\n" + Arrays.toString(file.list()));//String 型別陣列
String[] txtFileNames = file.list((dir, name) -> name.endsWith(".txt") && new File(dir, name).length() > 5 * 1024);
System.out.println("\n帶過濾功能\n" + Arrays.toString(txtFileNames));
File[] mp3Files = file.listFiles((dir, name) -> name.endsWith(".mp3") && new File(dir, name).length() > 5 * 1024);//File 型別陣列
System.out.println("\n獲取【檔案】列表\n" + Arrays.toString(mp3Files));
}
其他常見操作
private static void printFileInfo(File file) {
System.out.println("------------------系統相關的常量------------------");
System.out.println("separatorChar:" + File.separatorChar);//【\】
System.out.println("separator:" + File.separator);//【\】最常用的
System.out.println("pathSeparatorChar:" + File.pathSeparatorChar);//【;】
System.out.println("pathSeparator:" + File.pathSeparator);//【;】
System.out.println("\n------------------基本資訊------------------");
System.out.println("名稱:" + file.getName());
System.out.println("型別:" + (file.isFile() ? "檔案" : (file.isDirectory() ? "目錄" : "檔案不存在")));
System.out.println("大小:" + FileUtils.getDataSize(file.length()));
System.out.println("上次修改時間:" + new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date(file.lastModified())));
System.out.println("\n------------------屬性資訊------------------");
System.out.println("是否存在:" + file.exists());
System.out.println("是否隱藏:" + file.isHidden());
System.out.println("是否可執行:" + file.canExecute());
System.out.println("是否可讀寫:" + (file.canRead() ? "可讀" : "不可讀") + "-" + (file.canWrite() ? "可寫" : "不可寫"));
System.out.println("\n------------------路徑資訊------------------");
System.out.println("路徑:" + file.getPath());//這裡的 Path 指的是 new File() 時傳進去的路徑,可能為相對路徑,也可能為絕對路徑
System.out.println("是否為絕對路徑:" + file.isAbsolute());//在Windows 上,如果路徑名的字首是後跟 "\\" 的碟符,或者是 "\\\\",那麼該路徑名是絕對路徑名
System.out.println("絕對路徑:" + file.getAbsolutePath());//【e:\】
System.out.println("父路徑:" + file.getParent());//如果沒有父目錄,比如【e:】,則返回 null
try {
System.out.println("規範路徑:" + file.getCanonicalPath());//【E:\】
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("\n------------------磁碟資訊------------------");
//注意,對於任何有效的檔案,下列操作獲取的都是此檔案所屬【磁碟】的容量,而非此【目錄或檔案】的容量
System.out.println("所在磁碟未分配容量:" + FileUtils.getDataSize(file.getUsableSpace()));
System.out.println("所在磁碟可用容量:" + FileUtils.getDataSize(file.getFreeSpace()));
System.out.println("所在磁碟容量:" + FileUtils.getDataSize(file.getTotalSpace()));
System.out.println("\n------------------延伸資訊------------------");
System.out.println("toString:" + file.toString());//toString 返回的內容就是 getPath
System.out.println("URI:" + file.toURI().toString());//【file:/e:/】
System.out.println("Path:" + file.toPath().toString());//【e:\】
System.out.println("根目錄:" + file.toPath().getRoot());//【e:\】
System.out.println("父目錄層級:" + file.toPath().getNameCount());//【2】代表有幾級父目錄
}
常用封裝的工具
遞迴遍歷目錄下的檔案
呼叫案例:
listDirFiles(file, null, true);
FilenameFilter filter = (dir, name) -> name.endsWith(".md") && new File(dir, name).length() > 10 * 1024;
listDirFiles(file, filter, false);
/**
* 獲取指定目錄及其子目錄下的指定格式檔案的檔案
*
* @param dirFile 要遍歷的目錄,必須是一個目錄
* @param filter 對檔案的過濾規則(不作用於目錄),如果要遍歷所有檔案請設為 null
* @param isContainDir 遍歷的結果中是否包含目錄本身
*/
public static List<File> listDirFiles(File dirFile, FilenameFilter filter, boolean isContainDir) {
if (dirFile == null || !dirFile.isDirectory()) {
System.out.println("不是一個目錄");
return null;
}
List<File> files = new ArrayList<>();
getDirFiles(files, dirFile, filter, isContainDir);
for (File file : files) {
System.out.println(file.getName());
}
System.out.println("------------------------【遍歷完成,檔案總數:" + files.size() + "】------------------------");
return files;
}
/**
* 對指定目錄中的檔案進行深度遍歷,並按照指定過濾器進行過濾,將過濾後的內容儲存到一個指定的集合中
*
* @param fileList 將結果儲存到指定的集合中。由於要遞迴遍歷,不能定義為區域性變數,否則每次遞迴時都是把結果放到了一個新的集合中
* @param dirFile 要遍歷的目錄,必須是一個目錄
* @param filter 對檔案的過濾規則(不作用於目錄),如果要遍歷所有檔案請設為 null
* @param isContainDir 遍歷的結果中是否包含目錄本身
*/
private static void getDirFiles(List<File> fileList, File dirFile, FilenameFilter filter, boolean isContainDir) {
if (dirFile == null || !dirFile.isDirectory()) {
return;
}
for (File file : dirFile.listFiles()) {//也可以使用listFiles()在獲取列表時直接過濾,注意這種方式檢索時不要遺漏了目錄檔案
if (file.isDirectory()) {
if (isContainDir) {
fileList.add(file);
}
getDirFiles(fileList, file, filter, isContainDir);//遞迴
} else { //這裡不需要判斷是否為檔案了,因為 listFiles 中的要麼是 isDirectory 要麼是 isFile
if (filter == null || filter.accept(dirFile, file.getName())) {//是否滿足過濾規則
fileList.add(file);
}
}
}
}
遞迴刪除目錄下的檔案
呼叫案例:
deleateFiles(file, null, true);
FilenameFilter filter = (dir, name) -> name.endsWith(".md") && new File(dir, name).length() > 10 * 1024;
deleateFiles(file, filter, false);
/**
* 刪除一個檔案,或刪除一個目錄下的所有檔案
*
* @param dirFile 要刪除的目錄,可以是一個檔案
* @param filter 對要刪除的檔案的匹配規則(不作用於目錄),如果要刪除所有檔案請設為 null
* @param isDeleateDir 是否刪除目錄,false時只刪除目錄下的檔案而不刪除目錄
*/
public static void deleateFiles(File dirFile, FilenameFilter filter, boolean isDeleateDir) {
if (dirFile.isDirectory()) {//是目錄
for (File file : dirFile.listFiles()) {
deleateFiles(file, filter, isDeleateDir);//遞迴
}
if (isDeleateDir) {
System.out.println("目錄【" + dirFile.getAbsolutePath() + "】刪除" + (dirFile.delete() ? "成功" : "失敗"));//必須在刪除檔案後才能刪除目錄
}
} else if (dirFile.isFile()) {//是檔案。注意 isDirectory 為 false 並非就等價於 isFile 為 true
String symbol = isDeleateDir ? "\t" : "";
if (filter == null || filter.accept(dirFile.getParentFile(), dirFile.getName())) {//是否滿足匹配規則
System.out.println(symbol + "- 檔案【" + dirFile.getAbsolutePath() + "】刪除" + (dirFile.delete() ? "成功" : "失敗"));
} else {
System.out.println(symbol + "+ 檔案【" + dirFile.getAbsolutePath() + "】不滿足匹配規則,不刪除");
}
} else {
System.out.println("檔案不存在");
}
}
生成格式良好的檔案目錄
效果演示
最簡單的使用方式:
listDirFilesNames(file, Config.newBuilder().build());
效果:
1 D:\部落格\Java
1.1 D:\部落格\Java\Openfire XMPP Smack RTC IM 即時通訊 聊天 MD.md
1.2 D:\部落格\Java\Proxy 動態代理 InvocationHandler CGLIB MD.md
2 D:\部落格\RxJava
2.1 D:\部落格\RxJava\RxJava RxBinding RxView 控制元件事件 MD.md
3 D:\部落格\UI
3.1 D:\部落格\UI\Glide 快取策略 記憶體快取 磁碟快取 圖片載入 MD.md
3.2 D:\部落格\UI\自定義View
3.2.1 D:\部落格\UI\自定義View\自定義Toast 土司 MD.md
4 D:\部落格\優化
4.1 D:\部落格\優化\LeakCanary 記憶體洩漏 監測 效能優化 簡介 原理 MD.md
------------------------【檔案總數:48】------------------------
可以定製的內容:
Config config = Config.newBuilder().format(true).showNum(false).maxLeval(2).filter(filter).space("\t").build();
listDirFilesNames(file, config);
效果:
D:\部落格\Java
D:\部落格\Java\Openfire XMPP Smack RTC IM 即時通訊 聊天 MD.md
D:\部落格\Java\Proxy 動態代理 InvocationHandler CGLIB MD.md
D:\部落格\RxJava
D:\部落格\RxJava\RxJava RxBinding RxView 控制元件事件 MD.md
D:\部落格\UI
D:\部落格\UI\Glide 快取策略 記憶體快取 磁碟快取 圖片載入 MD.md
D:\部落格\UI\自定義View
D:\部落格\優化
D:\部落格\優化\LeakCanary 記憶體洩漏 監測 效能優化 簡介 原理 MD.md
------------------------【檔案總數:42】------------------------
程式碼
/**
* 獲取指定目錄及其子目錄下的指定格式檔案的檔名,並對檔名進行格式化
*/
public static List<String> listDirFilesNames(File dirFile, Config config) {
List<String> list = new ArrayList<>();
getDirFormatFilesNames(list, dirFile, config, 0, null);
for (String path : list) {
System.out.println(path);
}
System.out.println("------------------------【檔案總數:" + list.size() + "】------------------------");
return list;
}
/**
* 獲取指定目錄及其子目錄下的指定格式檔案的檔名,並對檔名進行格式化,並存儲到一個指定的集合中
*
* @param filePathList 將結果儲存到指定的集合中
* @param dirFile 要遍歷的目錄,必須是一個目錄
*/
private static void getDirFormatFilesNames(List<String> filePathList, File dirFile, Config config, int curLeval, String indexBegin) {
if (dirFile == null || !dirFile.isDirectory()) {
System.out.println("不是一個目錄");
return;
}
if (curLeval < config.maxLeval) {
curLeval++;
File[] files = dirFile.listFiles();
StringBuilder filePath;
for (int i = 0; i < files.length; i++) {
filePath = new StringBuilder();
if (config.format) {//格式化
for (int j = 1; j < curLeval; j++) {
filePath.append(config.space);//縮排
}
}
String curIndex = config.showNum ? (indexBegin == null || indexBegin.equals("") ? (i + 1) + "" : (indexBegin + "." + (i + 1))) : ""; //序號
filePath.append(curIndex).append(" ").append(files[i].getAbsolutePath());//路徑
if (files[i].isDirectory()) {//目錄,遞迴
filePathList.add(filePath.toString());
getDirFormatFilesNames(filePathList, files[i], config, curLeval, curIndex);//遞迴
} else if (config.filter == null || config.filter.accept(dirFile, files[i].getName())) {//檔案,判斷是否滿足過濾規則
filePathList.add(filePath.toString());
}
}
}
}
配置 Config
public class Config {
public FilenameFilter filter; //只遍歷目錄中的指定型別檔案,如果要遍歷所有檔案請設為null
public boolean format; //是否格式化
public boolean showNum;//是否顯示編號
public int maxLeval;//要遍歷的最大層級(多少層目錄)
public String space; //每一級目錄新增的符號,format為true時有效
private Config(Builder builder) {
filter = builder.filter;
format = builder.format;
showNum = builder.showNum;
maxLeval = builder.maxLeval;
space = builder.space;
}
public static Builder newBuilder() {
return new Builder();
}
public static final class Builder {
private FilenameFilter filter = null;
private boolean format = true;
private boolean showNum = true;
private int maxLeval = Integer.MAX_VALUE;
private String space = " |____";
private Builder() {
}
public Builder filter(FilenameFilter val) {
filter = val;
return this;
}
public Builder format(boolean val) {
format = val;
return this;
}
public Builder showNum(boolean val) {
showNum = val;
return this;
}
public Builder maxLeval(int val) {
maxLeval = val;
return this;
}
public Builder space(String val) {
space = val;
return this;
}
public Config build() {
return new Config(this);
}
}
}
格式化檔案大小
/**
* 格式化檔案大小
* @param size 檔案大小
*/
public static String getDataSize(long size) {
DecimalFormat formater = new DecimalFormat("####.00");
if (size < 1024) return size + "B";
else if (size < Math.pow(1024, 2)) return formater.format(size * Math.pow(1024, -1)) + "KB";
else if (size < Math.pow(1024, 3)) return formater.format(size * Math.pow(1024, -2)) + "MB";
else if (size < Math.pow(1024, 4)) return formater.format(size * Math.pow(1024, -3)) + "GB";
else if (size < Math.pow(1024, 5)) return formater.format(size * Math.pow(1024, -4)) + "TB";
else return "";
}
檔案複製的幾種方式
速度比較
public static void main(String[] args) throws IOException {
new File(FILE_PATH2).delete();
long start = System.currentTimeMillis();
copyFileByBuffer(FILE_PATH, FILE_PATH2);//14-23毫秒
//copyFileByByteArray(FILE_PATH, FILE_PATH2);//4-6毫秒
//copyFileByByteArray2(FILE_PATH, FILE_PATH2);//3-5毫秒
//copyFileByByte(FILE_PATH, FILE_PATH2);//700-800毫秒
//copyFileByByteOnce(FILE_PATH, FILE_PATH2);//2-4毫秒
//copyFileByBufLine(FILE_PATH, FILE_PATH2);//28-78毫秒
//copyFileByCharArray(FILE_PATH, FILE_PATH2);//14-22毫秒
//copyFileByChar(FILE_PATH, FILE_PATH2);//60-80毫秒
System.out.println("耗時:" + (System.currentTimeMillis() - start));
}
copyFileByBuffer
public static void copyFileByBuffer(String from, String to) {
try {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(from));
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(to));
int ch;
while ((ch = inputStream.read()) != -1) {
outputStream.write(ch); //先讀取到一個緩衝容器後再寫入
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
copyFileByByteArray
public static void copyFileByByteArray(String from, String to) {
try {
FileInputStream inputStream = new FileInputStream(from);
FileOutputStream outputStream = new FileOutputStream(to);
byte[] buf = new byte[1024];
int length;
while ((length = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, length); //一次讀取一個指定長度陣列的位元組
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
copyFileByByteArray2
public static boolean copyFileByByteArray2(String from, String to) {
try {
FileInputStream inputStream = new FileInputStream(from);
FileOutputStream outputStream = new FileOutputStream(to);
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
arrayOutputStream.write(buffer, 0, length);//一次讀取一個指定長度陣列的位元組
}
arrayOutputStream.writeTo(outputStream);
inputStream.close();
outputStream.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
copyFileByByte
public static void copyFileByByte(String from, String to) {
try {
FileInputStream inputStream = new FileInputStream(from);
FileOutputStream outputStream = new FileOutputStream(to);
int ch;
while ((ch = inputStream.read()) != -1) {
outputStream.write(ch); //一次讀取一個位元組
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
copyFileByByteOnce
public static void copyFileByByteOnce(String from, String to) {
try {
FileInputStream inputStream = new FileInputStream(from);
FileOutputStream outputStream = new FileOutputStream(to);
byte[] buf = new byte[inputStream.available()];
inputStream.read(buf); //一次讀取全部位元組
outputStream.write(buf);
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
copyFileByBufLine
public static void copyFileByBufLine(String from, String to) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(from), CHARSET));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(to), CHARSET));
String line;
while ((line = reader.readLine()) != null) {
writer.write(line); //一次寫入一行字元
writer.newLine();// 寫入一個行分隔符
writer.flush();
}
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
copyFileByCharArray
public static boolean copyFileByCharArray(String from, String to) {
try {
InputStreamReader reader = new InputStreamReader(new FileInputStream(from), CHARSET);
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(to), CHARSET);
char[] buf = new char[1024];
int len;
while ((len = reader.read(buf)) != -1) {
writer.write(buf, 0, len); //一次寫入指定個數的字元
writer.flush();
}
reader.close();
writer.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
copyFileByChar
public static boolean copyFileByChar(String from, String to) {
try {
InputStreamReader reader = new InputStreamReader(new FileInputStream(from), CHARSET);
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(to), CHARSET);
int ch;
while ((ch = reader.read()) != -1) {
writer.write(ch);//一次寫入一個字元
}
reader.close();
writer.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
2018-11-25