面試題:JavaIO流分類詳解與常用流用法實例


Java流概念:

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
//文件字符輸入流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
//文件字節輸入流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
//文件字符輸出流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

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

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

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

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

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(); } }
  • 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
  • 34
版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/zhangliangzi/article/details/51226652


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM