IO(Input/Output)作爲Java編程語言的核心之一其重要性不言而喻,其實現了Java程序對外界的訪問和輸出,學好Java也是建立在熟練掌握IO的基礎之上。其提供了對文件數據操作功能,在學習時要清晰掌握其可能發生特殊異常(有些異常編譯器也發現不了,而IO中方法絕大多數都會拋出異常)的方法,比如read需要結束標記、緩衝流的write方法還有flush()等等。
System.out.println(data);
這段簡單的輸出語句是我們在Java編程時用到的最頻繁的語句之一,其實這是一個標準的輸出流,用於將字符串輸出到屏幕上,也可以將其重定向到另一個輸出目標。
流(Stream)的概念很形象,其爲一組有序的數據序列。按照數據類型可以分類爲字符流和字節流,字符流是對輸入字符進行字符編碼得到的流,字節流是指可以用計算機處理的二進制數據或者指令所組成的流。兩者根據操作類型,可以大致劃分爲四大類,其中輸入流爲OutputStream(字節輸出流)和Writer(字符輸出流),輸入流爲InputStream(字節輸入流)和Reader(字符輸入流),這四大類均爲抽象類(Abstract Class),其各自的子類全部存放在java.io包中,它們協同完成了Java對數據的操作。
OutputStream與其子類的層次結構
OutputStream是所有字節輸出流的超類,其處理的是一串串二進制數據,與InputStream(字節輸入流)通過byte數組傳遞二進制數據。我們通過一個簡單地實例瞭解一下流在數據操作中過程。
/*
實現功能:將與java文件同目錄下的in.txt中內容複製到out.txt中
*/
import java.io.*;
class IODemo {
public static void main(String[] args) {
FileInputStream input = null;
FileOutputStream output = null;
try {
File in = new File("in.txt");
if(!in.exists())
throw new FileNotFoundException("文件in.txt不存在"); //若in.txt不存在,則拋異常退出程序
input = new FileInputStream(in); //指定輸入流的源
output = new FileOutputStream("out.txt", true); //指定輸出流的目標
int len;
byte buff[] = new byte[4];
while((len=input.read(buff)) != -1) { //輸出流將文件內容讀入buff數組中,並返回讀入字節總數
output.write(buff, 0, len); //將buff數組中從0開始len個字節寫入輸出流中
}
input.close(); //關閉I/O流
output.close();
} catch(FileNotFoundException e) { //對可能拋出的異常進行預處理
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
} catch(NullPointerException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}
從上面代碼中可以看到input輸入流先將一定長度的文件內容寫入在buff數組中,而後經輸出流讀取同樣長度的字節寫入到寫入目標中,就這樣完成了一次IO。有一點需要注意下,每個漢字字符佔用兩個字節,在截取操作的時候一定要做好判斷是否爲一個字符的二進制形式結尾,否則會出現我們常說的亂碼。
緩存是IO的一種性能優化。緩存流爲IO流增加了內存緩衝區。有了緩存區,使得在流上執行skip() mark() reset()方法都成爲可能。在使用緩存輸出流時要注意數據並沒有立刻被寫入至流中,而是首先進入緩存區。如果想立刻將緩存區中數據寫入輸出流中,一定要調用flush方法。flush方法就是用於即使緩衝區沒有滿的情況下,也將緩衝區的內容強制寫入到輸出目標中,習慣稱之爲刷新。該方法只對使用緩存區的OutputStream類的子類生效,當調用close方法時,系統在關閉流之前,也會將緩存區中信息刷新到輸出目標中。