轉:http://www.cnblogs.com/moonpool/p/5488463.html
http://blog.csdn.net/zhangliangzi/article/details/51226652
Java輸入/輸出流體系中常用的流分類(表內容來自java瘋狂講義)
注:下表中帶下劃線的是抽象類,不能創建對象。粗體部分是節點流,其他就是常用的處理流。
流分類 | 使用分類 | 字節輸入流 | 字節輸出流 | 字符輸入流 | 字符輸出流 |
抽象基類 | InputStream |
OutputStream |
Reader | Writer | |
節點流 | 訪問文件 | FileInputStream | FileOutStream | FileReader | FileWriter |
訪問數值 | ByteArrayInputStream | ByteArrayOutStream | CharArrayReader | CharArrayWriter | |
訪問管道 | PipedInputStream | PipedOutStream | PipedReader | PipedWriter | |
訪問字符串 | StringReader | StringWriter | |||
處理流 | 緩衝流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
轉換流 | InputStreamReader | OutputStreamWriter | |||
對象流 | ObjectInputStream | ObjectOutputStream | |||
抽象基類(過濾) | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | |
打印流 | PrintStream | PrintWriter | |||
推回輸入流 | PushbackInputStream | PushbackReader | |||
特殊流 | DataInputStream | DataOutputStream |
——————————————————————————————————————————————————————————————————
總結:
1.Java IO是採用的是裝飾模式,即採用處理流來包裝節點流的方式,來達到代碼通用性。
2.處理流和節點流的區分方法,節點流在新建時需要一個數據源(文件、網絡)作爲參數,而處理流需要一個節點流作爲參數。
3.處理流的作用就是提高代碼通用性,編寫代碼的便捷性,提高性能。
4.節點流都是對應抽象基類的實現類,它們都實現了抽象基類的基礎讀寫方法。其中read()方法如果返回-1,代表已經讀到數據源末尾。
Java把所有的有序數據都抽象成流模型,簡化了輸入輸出,理解了流模型就理解了Java IO。可以把流想象成水流,裏面的水滴有序的朝某一方向流動。水滴就是數據,且代表着最小的數據流動單位,在字節流中,水滴就是一字節(byte),在字符流中,水滴就是一字符(char)。
Java流的分類方法大致分爲以下幾種:
1、按流向劃分,分爲輸入流、輸出流
請注意,這裏的流向是以程序的運行時內存爲參照的。
輸入流類名中包含關鍵字InputStream或Reader,輸出流類名中包含關鍵字OutputStream或Writer。
2、按操作的數據單元類型劃分,分爲字節流、字符流
字節流操作的數據單元是8位的字節(byte),字符流操作的是16位的字符。
字節流類名中包含關鍵字InputStream或OutputStream,字符流類名中包含關鍵字Reader或Writer。
請注意,系統輸入輸出(System.in與System.out)都爲字節流。
3、按流的角色來劃分,分爲節點流與處理流
節點流是指程序可以向一個特定的節點讀寫數據,直接連接數據源;
這個節點最常見的是文件,類名中包含關鍵字File;還可以是數組、管道、字符串,關鍵字分別爲ByteArray/CharArray,Piped,String。
處理流並不直接連接數據源,它大多情況是對已存在的節點流進行包裝,是一種典型的裝飾器設計模式。使用處理流主要是爲了更方便的執行輸入輸出工作,如PrintStream,輸出功能很強大,推薦輸出時都使用處理流包裝。
注意:一個IO流可以即是輸入流又是字節流又或是以其他方式分類的流類型,是不衝突的。比如FileInputStream,它既是輸入流又是字節流還是文件節點流。
4、一些特別的的流類型
轉換流,轉換流只有字節流轉換爲字符流,因爲字符流使用起來更方便,我們只會向更方便使用的方向轉化。如:InputStreamReader與OutputStreamWriter。
緩衝流,有關鍵字Buffered,也是一種處理流,爲其包裝的流增加了緩存功能,提高了輸入輸出的效率,增加緩衝功能後需要使用flush()才能將緩衝區中內容寫入到實際的物理節點。但是,在現在版本的Java中,只需記得關閉輸出流(調用close()方法),就會自動執行輸出流的flush()方法,可以保證將緩衝區中內容寫入。
對象流,有關鍵字Object,主要用於將目標對象保存到磁盤中或允許在網絡中直接傳輸對象時使用(對象序列化),具體可參看博客Java序列化與反序列化。
推回輸入流,有關鍵字PushBack,當程序調用推回輸入流的unread()方法時,系統回把指定數組內容的內容推回到一個推回緩衝區中,在調用read()方法讀入內容時,就先從推回緩衝區中讀取,直到讀完推回緩衝區中內容後纔會從原輸入流中讀取。
必須要掌握的流用法實例:
1、FileInputStream\FileOutputStream\FileReader\FileWriter(使用方法類似)
//文件字節輸入流FileInputStream用法
public class TestFileIO1 {
public static void main(String[] args)throws IOException{
//此處路徑可以使用相對路徑與絕對路徑
FileInputStream fileInputStream = new FileInputStream("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO1.java");
//一個字節數組作爲緩衝,意爲每次讀取1024個字節,提高效率
byte[] buffer = new byte[1024];
//記錄讀取的字節數
int hasRead = 0;
//調用read()方法,返回實際讀取的字節數
while((hasRead = fileInputStream.read(buffer)) > 0){
System.out.print(new String(buffer, 0, hasRead));
}
//關閉流
fileInputStream.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
//文件字符輸入流FileReader用法
public class TestFileIO2 {
public static void main(String[] args)throws IOException{
FileReader fileReader = new FileReader("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO2.java");
char[] buffer = new char[32];
int hasRead = 0;
while((hasRead = fileReader.read(buffer)) > 0){
System.out.print(new String(buffer, 0, hasRead));
}
fileReader.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
//文件字節輸入流FileInputStream與文件字節輸出流FileOutputStream結合
public class TestFileIO3 {
public static void main(String[] args)throws IOException{
File result = new File("output.txt");
FileInputStream fileInputStream = new FileInputStream("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO3.java");
FileOutputStream fileOutputStream = new FileOutputStream(result);
byte[] buffer = new byte[1024];
int hasRead = 0;
while((hasRead = fileInputStream.read(buffer)) > 0){
fileOutputStream.write(buffer, 0, hasRead);
}
System.out.println(result.getAbsolutePath());
fileInputStream.close();
fileOutputStream.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
//文件字符輸出流FileWriter用法
public class TestFileIO4 {
public static void main(String[] args)throws IOException{
File result = new File("output.txt");
FileWriter fileWriter = new FileWriter(result);
fileWriter.write("飛流直下三千尺,\r\n");
fileWriter.write("疑是銀河落九天.\r\n");
fileWriter.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
2、輸出處理流PrintStream用法
public class TestFileIO5 {
public static void main(String[] args)throws IOException{
File result = new File("output.txt");
FileOutputStream fileOutputStream = new FileOutputStream(result);
//PrintStream處理流功能極其強大,所有字節輸出流都應使用PrintStream包裝
PrintStream printStream = new PrintStream(fileOutputStream);
printStream.println("牀前明月光,");
fileOutputStream.close();
printStream.close();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
3、轉換流inputStreamReader與緩衝流BufferedReader用法
public class TestFileIO6 {
public static void main(String[] args)throws IOException{
//系統輸入爲System.in,默認爲從鍵盤輸入,是字節輸入流InputStream類型
//使用轉換流將InputStream轉換爲Reader字符輸入流對象
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
//將Reader包裝爲字符緩存處理流BufferedReader對象
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//定義緩存行
String bufferString = null;
//使用BufferedReader特色readLine()方法逐行讀取輸入
while((bufferString = bufferedReader.readLine()) != null){
//直到輸入exit,停止程序
if(bufferString.equals("exit")){
System.exit(0);
}
//控制檯輸出輸入內容
System.out.println("輸入內容爲:" + bufferString);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
4、推回輸入流PushbackInputStream
//通過一個返回某個字符串之前的文件內容的demo,理解推回輸入流的讀取緩存機制
public class TestFileIO7 {
public static void main(String[] args)throws IOException{
//創建一個推回字節輸入流對象,指定緩衝區爲64
PushbackReader pushbackInputStream = new PushbackReader(new FileReader("D:\\Git\\TCCP\\IO\\src\\package1\\TestFileIO7.java"), 64);
char[] buffer = new char[32];
//記錄上次讀取的字符串
String lastContent = "";
int hasRead = 0;
while((hasRead = pushbackInputStream.read(buffer)) > 0){
//將讀取的字符轉換爲字符串
String content = new String(buffer, 0, hasRead);
int targetIndex = 0;
//將上次讀取的字符串和本次讀取的字符串拼接
//查找拼接後的字符串是否包含"new PushbackReader"(文件爲此段源代碼),返回位置由targetIndex記錄
if((targetIndex = (lastContent + content).indexOf("targetIndex")) > 0){
//將拼接後字符串轉化成字符數組後推回緩衝區
String newContent = lastContent + content;
pushbackInputStream.unread(newContent.toCharArray());
//定義一個長度爲targetIndex的char數組,如果新大小大於32,則需要重新定義
if(targetIndex > 32){
buffer = new char[targetIndex];
}
//再次讀取targetIndex長度的內容,其實就是目標字符串之前的內容
pushbackInputStream.read(buffer, 0, targetIndex);
//輸出結果
System.out.println(new String(buffer, 0, targetIndex));
//退出程序
System.exit(0);
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
5、重定向標準輸入\輸入
Java的標準輸入爲System.in默認爲鍵盤輸入,標準輸入爲System.out默認爲屏幕輸出。可通過setInt(InputStream in)方法與setOut(PrintStream out)方法修改(在這裏,連標準輸出的字節輸出流都被包裝成了PrintStream,我們在編程時有什麼理由不適用輸出流呢?)。
public class TestFileIO8 {
public static void main(String[] args)throws IOException{
FileInputStream fileInputStream = new FileInputStream("input.txt");
//重定向默認輸入
System.setIn(fileInputStream);
//一次性創建PrintStream輸出流對象(先創建文件字節輸出流對象,再包裝)
PrintStream printStream = new PrintStream(new FileOutputStream("output.txt"));
//重定向默認輸出
System.setOut(printStream);
//獲取System.in(input.txt文件中)的輸入
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
//下面這段標準輸出會輸出在Output.txt中
System.out.println("輸入的內容爲:" + scanner.next());
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
6、對象處理流ObjectInputStream\ObjectOutputStream
對象要想保存在磁盤或在網絡上傳輸,其實體類必須可序列化,它是將對象轉化爲字節序列,使其可以脫機運行。
要想實現序列化,實體類必須實現java.io.serializable接口。
//創建一個可序列化的實體類
public class Person implements Serializable{
private String username;
private int age;
public Person(String username, int age){
this.username = username;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class TestObjectIO {
public static void main(String[] args) throws Exception{
//ObjectOutputStream是一個處理流,必須建立在節點流上才能工作
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("output.txt"));
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("output.txt"));
objectOutputStream.writeObject(new Person("Leeon", 21));
Person person = (Person)objectInputStream.readObject();
System.out.println(person.getUsername() + person.getAge());
objectInputStream.close();
objectOutputStream.close();
}
}