簡介
Java 的標準庫 java.io 提供了 File 對象來操作文件和目錄。
一、File對象
1. 構造 File 對象時,既可以傳入絕對路徑,也可以傳入相對路徑。絕對路徑是以根目錄開頭的完整路徑。
File f = new File("D:\\Notepad++");
可以用 .
表示當前目錄,..
表示上級目錄。
// 假設當前目錄是C:\Docs
File f1 = new File("sub\\javac"); // 絕對路徑是C:\Docs\sub\javac
File f3 = new File(".\\sub\\javac"); // 絕對路徑是C:\Docs\sub\javac
File f3 = new File("..\\sub\\javac"); // 絕對路徑是C:\sub\javac
2.File 對象有3種形式表示的路徑,一種是 getPath()
,返回構造方法傳入的路徑,一種是 getAbsolutePath()
,返回絕對路徑,一種是 getCanonicalPath
,它和絕對路徑類似,但是返回的是規範路徑。
File f = new File("..");
System.out.println(f.getPath()); //打印:..
System.out.println(f.getAbsolutePath()); //打印:E:\IdeaProject\news1\..
System.out.println(f.getCanonicalPath()); //打印:E:\IdeaProjec
解釋: 絕對路徑可以表示成 C:\Windows\System32\..\notepad.exe
,而規範路徑就是把 .
(表示當前目錄)和 ..
(表示上級目錄)轉換成標準的絕對路徑後的路徑:C:\Windows\notepad.exe。
3.File 對象有一個靜態變量用於表示當前平臺的系統分隔符:
// 根據當前平臺打印"\"或"/"
System.out.println(File.separator);
4.File對象既可以表示文件,也可以表示目錄。
File f1 = new File("C:\\Windows");
System.out.println(f1.isFile()); //判斷該File對象是否是一個已存在的文件
System.out.println(f1.isDirectory()); //判斷該File對象是否是一個已存在的目錄
判斷文件的權限和大小:
- boolean canRead(): 是否可讀;
- boolean canWrite(): 是否可寫;
- boolean canExecute(): 是否可執行;
- long length(): 文件字節大小。
5.創建和刪除文件
File file = new File("/path/to/file");
if (file.createNewFile()) {
// 文件創建成功:
// 業務代碼。。。
if (file.delete()) {
// 刪除文件成功:
}
}
//創建一個臨時文件
File f = File.createTempFile("tmp-", ".txt"); // 提供臨時文件的前綴和後綴
f.deleteOnExit(); // JVM退出時自動刪除
6.遍歷文件和目錄
File f = new File("C:\\Windows");
File[] fs1 = f.listFiles(); // 列出所有文件和子目錄
// 僅列出.exe文件,返回true表示接受該文件
File[] fs2 = f.listFiles((dir, name) -> name.endsWith(".exe"));
File對象如果表示一個目錄,可以通過以下方法創建和刪除目錄:
- boolean mkdir(): 創建當前File對象表示的目錄;
- boolean mkdirs(): 創建當前File對象表示的目錄,並在必要時將不存在的父目錄也創建出來;
- boolean delete(): 刪除當前File對象表示的目錄,當前目錄必須爲空才能刪除成功。
7.Path
java 標準庫還提供了一個 Path 對象,它位於 java.nio.file
包。Path 對象和 File 對象類似,但操作更加簡單:
Path p1 = Paths.get(".", "project", "study"); // 構造一個Path對象
System.out.println(p1);
Path p2 = p1.toAbsolutePath(); // 轉換爲絕對路徑
System.out.println(p2);
Path p3 = p2.normalize(); // 轉換爲規範路徑
System.out.println(p3);
File f = p3.toFile(); // 轉換爲File對象
System.out.println(f);
for (Path p : Paths.get("..").toAbsolutePath()) { // 可以直接遍歷Path
System.out.println(" " + p);
}
二、InputStream
InputStream 就是 Java 標準庫提供的最基本的輸入流。InputStream 並不是一個接口,而是一個抽象類,它是所有輸入流的超類。這個抽象類定義的一個最重要的方法就是 int read()
1.FileInputStream
FileInputStream 是 InputStream 的一個子類,他可以從文件流中讀取數據。
public void readFile() throws IOException {
// 創建一個FileInputStream對象:
InputStream input = new FileInputStream("file/readme.txt");
for (;;) {
int n = input.read(); // 反覆調用read()方法,直到返回-1(表示結束)
if (n == -1)
break;
System.out.println(n); // 打印byte的值
}
input.close(); // 關閉流
}
讀取過程中發生了 IO 錯誤拋出了異常,InputStream 就沒法正確地關閉。因此需要用try ... finally
來保證 InputStream 在無論是否發生 IO 錯誤的時候都能夠正確地關閉:
public void readFile() throws IOException {
InputStream input = null;
try {
input = new FileInputStream("file/readme.txt");
int n;
while ((n = input.read()) != -1) { // 利用while同時讀取並判斷
System.out.println(n);
}
} finally {
if (input != null) { input.close(); }
}
}
或者用下面這種簡化版:
public void readFile() throws IOException {
try (InputStream input = new FileInputStream("src/readme.txt")) {
int n;
while ((n = input.read()) != -1) {
System.out.println(n);
}
} // 編譯器在此自動爲我們寫入finally並調用close()
}
解釋: 編譯器並不會特別地爲 InputStream 加上自動關閉。編譯器只看try(resource = ...)
中的對象是否實現了 java.lang.AutoCloseable
接口,如果實現了,就自動加上finally語句並調用 close()
方法。InputStream 和 OutputStream 都實現了這個接口,因此,都可以用上面這種寫法。
2.緩衝
很多流支持一次性讀取多個字節到緩衝區,對於文件和網絡流來說,利用緩衝區一次性讀取多個字節效率往往要高很多。InputStream 提供了兩個重載方法來支持讀取多個字節:
- int read(byte[] b): 讀取若干字節並填充到 byte[] 數組,返回讀取的字節數
- int read(byte[] b, int off, int len): 指定 byte[] 數組的偏移量和最大填充數
try (InputStream input = new FileInputStream("file/readme.txt")) {
// 定義1000個字節大小的緩衝區:
byte[] buffer = new byte[1000];
int n;
while ((n = input.read(buffer)) != -1) { // 讀取到緩衝區
System.out.println("read " + n + " bytes.");
}
}
3.阻塞
read()
方法是阻塞(Blocking)的,意思是每次執行 read()
方法必須等待該方法返回才能執行下一行代碼,讀取IO流相比執行普通代碼,速度會慢很多。
三、OutputStream
OutputStream 是 Java 標準庫提供的最基本的輸出流。它也是抽象類,它是所有輸出流的超類。這個抽象類定義的一個最重要的方法就是 void write(int b)
1.FileOutputStream
//一次寫入一個字節
OutputStream output = new FileOutputStream("out/readme.txt");
output.write(72); // 寫入字母H
output.close();
//一次性寫入若干字節
OutputStream output = new FileOutputStream("out/readme.txt");
//或者用下面的方式保證後寫入的內容不會覆蓋前面的內容
//OutputStream output = new FileOutputStream("out/readme.txt", true);
output.write("Hello".getBytes("UTF-8")); // 寫入字符串Hello
output.close();
避免發生 IO 異常而無法關閉流的寫法:
try (OutputStream output = new FileOutputStream("out/readme.txt")) {
output.write("Hello".getBytes("UTF-8")); // Hello
} // 編譯器在此自動爲我們寫入finally並調用close()
四、參考文檔
https://www.liaoxuefeng.com/wiki/1252599548343744/1255945227202752