Java開發筆記(八十五)經過字符流讀寫文件

前面介紹了文件的信息獲取、管理操做,以及目錄下的文件遍歷,那麼文件內部數據又是怎樣讀寫的呢?這正是本文所要闡述的內容。File工具當然強大,但它並不能直接讀寫文件,而要藉助於其它工具方能開展讀寫操做。對於寫操做來講,須要經過文件寫入器FileWriter搭配File工具才行。建立寫入器對象的過程很簡單,只要在調用FileWriter的構造方法時傳遞文件對象便可,接着就能調用寫入器的下列方法向文件寫入數據了。
write:往文件寫入字符串。注意該方法存在多個同名的重載方法。
append:也是往文件寫入字符串。按字面意思,append方法像是往文件末尾追加字符串,然而並不是如此,append方法與write方法的寫入位置是一樣的。兩者的區別在於,append方法會把空指針看成「null」寫入文件,而write方法不支持寫入空指針。
close:關閉文件寫入器。
把文件的一系列寫入操做串起來,造成如下流程的寫文件代碼,注意文件寫入器的幾個方法均需捕捉輸入輸出異常IOException:html

	private static String mFileName = "D:/test/aac.txt";
	// 存在隱患的寫文件代碼。發生異常時不會關閉文件
	private static void writeFileSimple() {
		String str = "白日依山盡,黃河入海流。\n";
		File file = new File(mFileName); // 建立一個指定路徑的文件對象
		try {
			FileWriter writer = new FileWriter(file); // 建立一個文件寫入器
			writer.write(str); // 往文件寫入字符串
			writer.close(); // 關閉文件
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

上面的例子代碼看似結構完整,實則存在不小的隱患。由於close方法只有在正常分支纔會被調用,異常分支並無調用該方法,如此一來,一旦異常發生,已經打開的文件將不會正常關閉,結果可能致使文件損壞。解決辦法是在try/catch後面補充finally語句,在finally語句塊中添加close方法的調用,因而改進後的寫文件代碼示例以下:java

	// 改進後的寫文件代碼。在finally代碼塊中關閉文件
	private static void writeFileWithFinally() {
		String str = "白日依山盡,黃河入海流。\n";
		File file = new File(mFileName); // 建立一個指定路徑的文件對象
		FileWriter writer = null;
		try {
			writer = new FileWriter(file); // 建立一個文件寫入器
			writer.write(str); // 往文件寫入字符串
		} catch (IOException e) {
			e.printStackTrace();
		} finally { // 不管是否遇到異常,都要釋放文件資源
			if (writer != null) {
				try {
					writer.close(); // 關閉文件
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

 

改進後的代碼確實消除了文件異常關閉的風險,但是整個代碼一會兒多出好些行,着實變得拖沓不小。爲此從Java7開始,try語句支持「try-with-resources」的表達式,意思是攜帶某些資源去嘗試幹活,並在嘗試結束後自動釋放這些資源。具體作法是在try後邊添加圓括號,並在圓括號內部填寫資源對象的建立語句,只要這個資源類實現了AutoCloseable接口,程序便會在try/catch結束後自動調用該資源的close方法。這樣就無需補充finally代碼塊,也無需顯式調用close方法了,採起資源自動管理的優化代碼以下所示:程序員

	// 採起自動釋放資源的寫文件代碼
	private static void writeFileWithTry() {
		String str = "白日依山盡,黃河入海流。\n";
		File file = new File(mFileName); // 建立一個指定路徑的文件對象
		// Java7的新增功能,在try(...)裏聲明的資源,會在try/catch結束後自動釋放。
		// 至關於編譯器自動補充了finally代碼塊中的資源釋放操做。
		// 資源類必須實現java.lang.AutoCloseable接口,這樣close方法纔會由系統調用。
		// 通常說來,文件I/O、套接字、數據庫鏈接等均已實現該接口。
		try (FileWriter writer = new FileWriter(file)) {
			writer.write(str); // 往文件寫入字符串
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

因而可知,使用「try-with-resources」方式的代碼頓時減小到了寥寥幾行,可謂程序員的一大福音。數據庫

和寫操做對應的是讀操做,讀文件用到了文件讀取器FileReader,它依然與File工具搭檔合做。建立讀取器對象也要在調用FileReader的構造方法時傳遞文件對象,讀取器提供的調用方法列舉以下:
skip:跳過若干字符。注意FileReader的skip方法跳過的是字符數,不是字節數。
read:從文件讀取數據到字節數組。注意該方法存在多個同名的重載方法。
close:關閉文件讀取器。
經過文件讀取器從文件中讀取數據的常規代碼示例以下:數組

	// 存在隱患的讀文件代碼。發生異常時不會關閉文件
	private static void readFileSimple() {
		File file = new File(mFileName); // 建立一個指定路徑的文件對象
		try {
			FileReader reader = new FileReader(file); // 建立一個文件讀取器
			//reader.skip(2); // 字符流的skip方法跳過的是字符數,不是字節數
			char[] temp = new char[(int) file.length()];
			reader.read(temp); // 從文件讀取數據到字節數組
			String content = new String(temp); // 把字符數組轉爲字符串
			System.out.println("content="+content);
			reader.close(); // 關閉文件
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

以上的讀文件代碼仍然沒有考慮到異常發生時候的資源釋放問題,於是須要增長finally語句加以改進,在finally代碼塊中調用close方法關閉文件,改進後的代碼以下所示:app

	// 改進後的讀文件代碼
	private static void readFileWithFinally() {
		File file = new File(mFileName); // 建立一個指定路徑的文件對象
		FileReader reader = null;
		try {
			reader = new FileReader(file); // 建立一個文件讀取器
			char[] temp = new char[(int) file.length()];
			reader.read(temp); // 從文件讀取數據到字節數組
			String content = new String(temp); // 把字符數組轉爲字符串
			System.out.println("content="+content);
		} catch (IOException e) {
			e.printStackTrace();
		} finally { // 不管是否遇到異常,都要釋放文件資源
			if (reader != null) {
				try {
					reader.close(); // 關閉文件
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

 

同FileWriter同樣,FileReader也實現了AutoCloseable接口,意味着它一樣適用於try-with-resources的規則。那麼將文件讀取器的建立語句放到try以後的圓括號中,以前的finally語句塊能夠整個刪除,由於程序會在try/catch結束後自動釋放讀取器資源。此時採起自動釋放資源的讀文件代碼變成了下面這樣:工具

	// 採起自動釋放資源的讀文件代碼
	private static void readFileWithTry() {
		File file = new File(mFileName); // 建立一個指定路徑的文件對象
		// Java7的新增功能,在try(...)裏聲明的資源,會在try/catch結束後自動釋放。
		// 至關於編譯器自動補充了finally代碼塊中的資源釋放操做。
		// 資源類必須實現java.lang.AutoCloseable接口,這樣close方法纔會由系統調用。
		// 通常說來,文件I/O、套接字、數據庫鏈接等均已實現該接口。
		try (FileReader reader = new FileReader(file)) {
			char[] temp = new char[(int) file.length()];
			reader.read(temp); // 從文件讀取數據到字節數組
			String content = new String(temp); // 把字符數組轉爲字符串
			System.out.println("content="+content);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 

別看上面的代碼還有好幾行,要是所有去掉註釋真沒多少行。省時省力的便捷寫法理應大力推廣,若無特殊狀況,日後的相關代碼將一概採用以上try-with-resources的寫法。優化



更多Java技術文章參見《Java開發筆記(序)章節目錄指針

相關文章
相關標籤/搜索