Java IO5:管道流、对象流
前言
前面的文章主要講了文件字符輸入流FileWriter、文件字符輸出流FileReader、文件字節輸出流FileOutputStream、文件字節輸入流FileInputStream,這些都是常見的流類。當然除了這些流類之外,Java還提供了很多的流類給用戶使用,本文就看一下別的流。
?
管道流
管道流主要用于連接兩個線程的通信。管道流也分為字節流(PipedInputStream、PipedOutputStream)和字符流(PipedReader、PipedWriter)。比如一個PipedInputStream必須和一個PipedOutputStream對象進行連接而產生一個通信管道,PipedOutputStream向管道中寫入數據,PipedInputStream從管道中讀取數據。管道流的工作如下圖所示:
下面看一下管道流的用法。既然管道流的作用是用于線程間的通信,那么勢必有發送線程和接收線程,兩個線程通過管道流交互數據。首先寫一個發送數據的線程:
public class Sender implements Runnable {private PipedOutputStream out = new PipedOutputStream();public PipedOutputStream getOutputStream(){return out;}public void run(){String str = "Receiver, 你好!";try{out.write(str.getBytes()); // 向管道流中寫入數據(發送)out.close();} catch (IOException e){e.printStackTrace();}} }用流寫數據的時候注意關注一下,該流是否支持直接寫String,不可以的話要用String的getBytes()方法獲取字符串的字節。既然有一個發送數據的線程了,接下來來一個接收數據的線程:
public class Receiver implements Runnable {private PipedInputStream in = new PipedInputStream();public PipedInputStream getInputStream(){return in;}public void run(){String s = null;byte b0[] = new byte[1024];try{int length = in.read(b0);if (-1 != length){s = new String(b0, 0 , length);System.out.println("收到了以下信息:" + s);}in.close();} catch (IOException e){e.printStackTrace();}} }兩個線程都有了,寫一個main線程,利用管道輸出流的connect方法連接管道輸出流和管道輸入流:
public static void main(String[] args) {try{Sender sender = new Sender();Receiver receiver = new Receiver();Thread senderThread = new Thread(sender);Thread receiverThread = new Thread(receiver);PipedOutputStream out = sender.getOutputStream(); // 寫入PipedInputStream in = receiver.getInputStream(); // 讀出out.connect(in);// 將輸出發送到輸入senderThread.start();receiverThread.start();} catch (IOException e){e.printStackTrace();} }輸出結果應該很明顯了,大家都知道,接收線程接收到了來自發送線程通過管道流輸出流發送的數據:
收到了以下信息:Receiver, 你好!注意一下,PipedInputStream運用的是一個1024字節固定大小的循環緩沖區,寫入PipedOutputStream的數據實際上保存到了對應的PipedInputStream的內部緩沖區。PipedInputStream執行讀操作時,讀取的數據實際上來自這個內部緩沖區。如果對應的PipedInputStream輸入緩沖區已滿,任何企圖寫入PipedOutputStream的線程都將被阻塞。而且這個寫操作線程將一直阻塞,直至出現讀取PipedInputStream的操作從緩沖區刪除數據。
這意味著,向PipedOutputStream寫入數據的線程不應該是負責從對應PipedInputStream讀取數據的唯一線程(所以這里開了兩個線程分別用于讀寫)。假定t線程試圖一次對PipedOutputStream的write()方法的調用中向對應的PipedOutputStream寫入2000字節的數據,在t線程阻塞之前,它最多能夠寫入1024字節的數據(PipedInputStream內部緩沖區的大小)。然而,一旦t被阻塞,讀取PipedInputStream的操作就再也不能出現了,因為t是唯一讀取PipedInputStream的線程,這樣,t線程已經完全被阻塞。
?
對象流
序列化,在這篇文章中已經講得比較清楚了,這一部分主要是再次簡單過一下對象流的知識而已。
Java中提供了ObjectInputStream、ObjectOutputStream這兩個類用于對象序列化操作,這兩個類是用于存儲和讀取對象的輸入輸出流類,只要把對象中的所有成員變量都存儲起來,就等于保存了這個對象,之后從保存的對象之中再將對象讀取進來就可以繼續使用此對象。ObjectInputStream、ObjectOutputStream可以幫助開發者完成保存和讀取對象成員變量取值的過程,但要求讀寫或存儲的對象必須實現了Serializable接口。
看一下例子,先來一個實現了Serializable接口的實體類Person:
public class Person implements Serializable {/*** 序列化*/private static final long serialVersionUID = 7827863437931135333L;private transient String name;private int age;private final static String sex = "man";public Person(String name, int age){this.name = name;this.age = age;}public String toString(){return "姓名:" + this.name + ", 年齡:" + this.age + ", 性別:" + sex;} }調用ObjectOutputStream和ObjectInputStream寫一個序列化和反序列化的方法,我現在D盤下沒有"serializable.txt":
public static void main(String[] args) throws Exception {File file = new File("D:/serializable.txt");serializable(file);deserializable(file); }// 序列化對象方法 public static void serializable(File file) throws Exception {OutputStream outputFile = new FileOutputStream(file);ObjectOutputStream oos = new ObjectOutputStream(outputFile);oos.writeObject(new Person("張三", 25));oos.close(); }// 反序列化對象方法 public static void deserializable(File file) throws Exception {InputStream inputFile = new FileInputStream(file);ObjectInputStream ois = new ObjectInputStream(inputFile);Person p = (Person)ois.readObject();System.out.println(p); }現在運行一下,D盤下多了一個"serializable.txt",文件里面的內容是:
看到亂碼,因為序列化之后本身就是按照一定的二進制格式組織的文件,這些二進制格式不能被文本文件所識別,所以亂碼也是正常的。
當然,控制臺上也是有輸出的:
姓名:null, 年齡:25, 性別:man這證明了被transient修飾的成員變量不會被序列化。
轉載于:https://www.cnblogs.com/qypx520/p/5736553.html
總結
以上是生活随笔為你收集整理的Java IO5:管道流、对象流的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爷爷在种花拼音怎么写
- 下一篇: 使用RxJava帮助低功耗蓝牙(BLE)