Java 高階程式設計-File檔案操作類
學習阿里雲大學零基礎學Java系列 Java高階程式設計
1. File類說明
在Java語言裡面提供有對於檔案作業系統操作的支援,而這個支援就在java.io.File類中進行了定義,也就是說在整個java.io包裡面,File類是唯一一個與檔案本身操作(建立、刪除、重新命名等)有關的類,而如果想進行File類的操作,必須要提供有完整的路徑,而後才可以呼叫相應的方法進行處理
2. File類的基本使用
開啟jdk文件可以發現,File類是Comparable介面的子類,所以File類的物件是可以進行排序處理的。而在進行File類處理的時候需要為其設定訪問路徑,那麼對於路徑的配置主要通過File類的構造方法處理。
- 構造方法 File(String pathname) 設定要操作的完整路徑
- 構造方法操作 File(String parent,String child) 設定父路徑與子目錄
如果想要進行檔案的基本操作,可以使用如下的方法:
- 建立新的檔案
public boolean createNewFile() throws IOException
- 判斷檔案是否存在
public boolean exists()
- 刪除檔案
public boolean delete()
範例:使用File類建立一個檔案(d:\mldn.txt)
package IOKnowledge;
import java.io.File;
public class IOTest {
public static void main(String[] args) throws Exception{
File file = new File("d:\\mldn.txt");
if (file.exists()) {
file.delete();// 刪除檔案
} else {
System.out.println(file.createNewFile()); // 建立新的檔案
}
}
}
通過程式碼可以發現,File類實現的就是檔案本身的處理
3. File類深入操作
現在已經實現了檔案的基礎操作,但是對於這個操作裡面也是存在有一些問題的,下面針對之前的程式碼進行優化處理
在實際的軟體專案開發和執行的過程中,往往都會在window中進行專案的開發,而在專案部署的時候基於Linux或Unix來進行專案的釋出以保證生產環境的安全性;
在不同的作業系統之中會存在不同的路徑分隔符:window分隔符“\”、LInux分隔符“/”,所以在最初進行開發的時候必須考慮不同系統環境下的分隔符的區別,所以為了解決此問題,File類提供有一個常量:
public static final String separator
(常量命名沒有大寫,歷史遺留問題)File file = new File("d:" + File.separator + "mldn.txt");
但是隨著系統的適應性的不斷加強,對於當前的路徑操作,也可以隨意使用了
File file = new File("d:/mldn.txt");// window系統下也支援此類書寫,但是推薦使用File提供的分隔符常量
在使用File類進行檔案處理時需要注意的是:程式->JVM->作業系統函式->檔案處理(程式通過jvm,然後呼叫作業系統函式,再在磁碟上實現檔案處理),所以在進行同一檔案反覆刪除和建立的時候有可能會出現有延遲的問題,所以這個時候最好的方案是別重名(例如使用UUID);
在進行檔案建立的時候有一個重要的前提:檔案的父路徑必須首先存在
File file = new File("d:" + File.separator + "hello" + File.separator + "demo" + File.separator + "message" + File.separator + "mldn.txt"); Exception in thread "main" java.io.IOException: 系統找不到指定的路徑。 at java.io.WinNTFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(Unknown Source) at IOKnowledge.IOTest.main(IOTest.java:23)
- 如何獲取父路徑
public File getParentFile()
- 父路徑不存在則建立目錄
public boolean mkdir()
建立單級路徑public boolean mkdirs()
建立多級路徑
package IOKnowledge; import java.io.File; public class IOTest { public static void main(String[] args) throws Exception{ File file = new File("d:" + File.separator + "hello" + File.separator + "demo" + File.separator + "message" + File.separator + "mldn.txt"); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs();// 建立父路徑 } if (file.exists()) { file.delete();// 刪除檔案 } else { System.out.println(file.createNewFile()); // 建立新的檔案 } } }
建立檔案的標準形式
這種判斷並且建立父目錄的操作在很多的情況下可能只需要一次,但是如果將這個判斷一直都停留在程式碼裡面,那麼就會造成時間複雜度的提升,所以這個時候如果要想提升效能,請先保證父目錄已經建立,然後刪除掉父目錄是否存在的驗證- 如何獲取父路徑
4. 獲取檔案資訊
除了可以進行檔案的操作之外也可以通過File類來獲取一些檔案本身提供的資訊,可以獲取如下內容:
- 檔案是否可讀
public boolean canRead()
- 檔案是否可寫
public boolean canWrite()
- 獲取檔案長度
public long length()
該方法返回的是long資料型別,位元組長度 - 最後一次修改日期時間
public long lastModified()
- 判斷是否是目錄
public boolean isDirectory()
- 判斷是否是檔案
public boolean isFile()
// 獲取檔案資訊
public static void main(String[] args) throws Exception{
File file = new File("d:" + File.separator + "hello" + File.separator + "demo" + File.separator + "message" + File.separator + "mldn.jpg");
System.out.println("檔案是否可讀:" + file.canRead());// 是否可讀
System.out.println("檔案是否可寫:" + file.canWrite());// 是否可寫
System.out.println("檔案大小:" + file.length() + "位元組");// 檔案大小
System.out.println("檔案大小:" + MathUtil.round(file.length() / (double)1024 / 1024, 2) + "MB");
System.out.println("最後的修改時間:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified())));
System.out.println("是否是目錄:" + file.isDirectory());
System.out.println("是否是檔案:" + file.isFile());
}
//數字工具類
class MathUtil {
private MathUtil() {};
public static double round(double num, int scale) {
return Math.round(Math.pow(10, scale) * num) / Math.pow(10, scale);
}
}
既然可以判斷給定的路徑是檔案還是目錄,那麼就可以進一步的判斷,如果發現是目錄,則應該列出目錄中的全部內容:
- 列出目錄內容:
public File[] listFiles()
public static void main(String[] args) {
File file = new File("d:" + File.separator);
if (file.isDirectory()) {// 當前是一個目錄
File [] result = file.listFiles();
for (int i = 0; i < result.length; i++) {
System.out.println(result[i]);
}
}
}
這些資訊的獲得都是檔案或目錄本身的操作,都是不涉及到我呢見內容處理的
5. File操作案例:列出指定目錄中的全部檔案
現在可以由開發者任意設定一個目錄的路徑,而後將這個目錄中所有的檔案的資訊全部列出,包括子目錄的所有檔案,在這樣的處理情況下最好的做法就是利用遞迴的形式來完成。
範例:程式實現
public static void main(String[] args) {
File file = new File("D:" + File.separator);// 是一個目錄
listDir(file);
}
public static void listDir(File file) {
if (file.isDirectory()) {// 是一個目錄
File [] result = file.listFiles();// 列出目錄中的全部內容
if (result != null) {
for (int i = 0; i < result.length; i++) {
listDir(result[i]);// 依次判斷執行
}
}
}
System.out.println(file);// 獲得完整路徑
}
如果現在將路徑輸出變為刪除操作,那麼就徹底刪除路徑了
6. File操作案例:批量修改檔名稱
編寫程式,程式執行時輸入目錄名稱,並把該目錄下的所有檔名字尾修改為.txt,對於這類的操作必須設定一些假設的約定,能夠重新命名的檔案都是有後綴的,如果沒有後綴的路徑,則為其追加路徑,如果有後綴的路徑,則必須以最後一個“.”進行擷取。
// 範例:檔案批量命名
public static void main(String[] args) {
File file = new File("D:" + File.separator + "hello" + File.separator);// 是一個目錄
long start = System.currentTimeMillis();
renameDir(file);
long end = System.currentTimeMillis();
System.out.println("本次操作花費時間:" + (end - start));
}
public static void renameDir(File file) {
if (file.isDirectory()) {// 是一個目錄
File [] results = file.listFiles();// 列出子目錄中的內容
if (results != null) {
for (int i = 0; i < results.length; i++) {
renameDir(results[i]);
}
}
} else {
if (file.isFile()) {// 如果是檔案則必須進行重新命名
String fileName = null;
if (file.getName().contains(".")) {
fileName = file.getName().substring(0, file.getName().lastIndexOf(".")) + ".txt";
} else {
fileName = file.getName() + ".txt";
}
File newFile = new File(file.getParentFile(), fileName);
file.renameTo(newFile);// 重新命名
System.out.println(newFile);
}
}
}
在面試的過程中經常會出現給一個路徑然後進行檔案批量修改操作,那麼就採用以上結構
注:上面的程式碼對於同一個目錄下相同的檔名但是有不同的字尾修改為同一個字尾時會有部分修改失敗,且程式不報錯,例如hello目錄下有hello.png和hello.jpg兩個檔案,批量修改為.txt字尾,會有一個修改成功,一個失敗。