Java IO學習筆記五

weixin_33785972發表於2017-05-25

管道流

  • 管道流的主要作用是可以進行兩個執行緒間的通訊,分為管道輸出流(PipedOutputStream)、管道輸入流(PipedInputStream),如果想要進行管道輸出,則必須要把輸出流連在輸入流之上,在PipedOutputStream類上有如下的一個方法用於連線管道:
    public void connect(PipedInputStream snk)throws IOException
  • 通常是建立兩個單獨的執行緒來實現通訊,如果是單個執行緒的話容易出現執行緒堵塞,因為輸出流最多隻能向緩衝區寫入1024個位元組的資料,如果超出就會出現執行緒堵塞,因此必須建立多個執行緒實現緩衝區的釋放和儲存

PipedOutputStream

  • 管道輸出流是管道的傳送端,可以將管道輸出流連線到管道輸入流來建立一個通訊管道,通常,資料由某個執行緒寫入 PipedOutputStream物件,並由其他執行緒從連線的 PipedInputStream 讀取。不建議對這兩個物件嘗試使用單個執行緒,因為這樣可能會造成該執行緒死鎖。如果某個執行緒正從連線的管道輸入流中讀取資料位元組,但該執行緒不再處於活動狀態,則該管道被視為處於 毀壞 狀態。

建構函式

  • PipedOutputStream() 建立尚未連線到管道輸入流的管道輸出流。
  • PipedOutputStream(PipedInputStream snk) 建立連線到指定管道輸入流的管道輸出流。

常用函式

  • close() 關閉
  • void connect(PipedInputStream snk) 將此管道輸出流連線到接收者。
  • void flush() 重新整理此輸出流並強制寫出所有緩衝的輸出位元組。
  • void write(byte[] b, int off, int len)len 位元組從初始偏移量為 off 的指定 byte 陣列寫入該管道輸出流。
  • void write(int b) 將指定 byte 寫入傳送的輸出流。

PipedInputStream

  • 管道輸入流應該連線到管道輸出流;管道輸入流提供要寫入管道輸出流的所有資料位元組。通常,資料由某個執行緒從 PipedInputStream 物件讀取,並由其他執行緒將其寫入到相應的 PipedOutputStream。不建議對這兩個物件嘗試使用單個執行緒,因為這樣可能死鎖執行緒。管道輸入流包含一個緩衝區,可在緩衝區限定的範圍內將讀操作和寫操作分離開。 如果向連線管道輸出流提供資料位元組的執行緒不再存在,則認為該管道已損壞。

建構函式

  • PipedInputStream() 建立尚未連線的 PipedInputStream
  • PipedInputStream(PipedOutputStream src) 建立 PipedInputStream,使其連線到管道輸出流 src

常用函式

  • int available() 返回可以不受阻塞地從此輸入流中讀取的位元組數。
  • void close() 關閉此管道輸入流並釋放與該流相關的所有系統資源。
  • void connect(PipedOutputStream src) 使此管道輸入流連線到管道輸出流 src
  • int read() 讀取此管道輸入流中的下一個資料位元組。
  • int read(byte[] b, int off, int len) 將最多 len 個資料位元組從此管道輸入流讀入 byte 陣列。
  • protected void receive(int b) 接收資料位元組。

例項

package IO;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

/**
 * Created by chenjiabing on 17-5-25.
 */

/**
 * 注意的問題:
 * 1.寫執行緒正在往緩衝區寫資料的時候,但是此時的讀執行緒的管道結束,那麼此時的寫執行緒的管道就會發生IOException異常
 * 2.讀執行緒正在從緩衝區讀資料的時候,但是此時的寫執行緒的管道已經結束了,此時就會引起讀執行緒的管道發生IOException異常
 * 3.必須是啟用多執行緒才能實現管道之間的讀寫,否則會出現堵塞現象,因為這裡的PipeOutputStream每次向緩衝區寫入的位元組數最大是1024,如果不及時的減少緩衝區的資料量就會出現堵塞
 */

public class demo7 {
    public static PipedOutputStream outputStream = new PipedOutputStream();
    public static PipedInputStream inputStream = new PipedInputStream();

    /**
     * 建立一個寫入資料程式,使用的是PipeOutStream,將資料寫入管道中
     */
    public static void send() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] bytes = new byte[2000];     //建立一個2000位元組的陣列
                while (true) {
                    try {
                        outputStream.write(bytes, 0, 2000);  //寫入管道,但是這裡的緩衝區最多寫入1024個位元組的資料,因此這個是一次沒有寫完
                        System.out.println("寫入成功");
                    } catch (IOException e) {
                        System.out.println("寫入失敗");
                        System.exit(1);
                    }
                }
            }
        }).start();
    }

    /**
     * 使用PipeInputStream建立一個讀取的執行緒
     */

    public static void receive() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] bytes = new byte[100];  //一次性只讀取100個位元組
                int len = 0;
                try {
                    len = inputStream.read(bytes, 0, 100);  //讀取
                    while (len != -1) {
                        System.out.println("已經讀取了" + len + "個位元組");
                        len = inputStream.read(bytes, 0, 100);
                    }


                } catch (IOException e) {
                    System.out.println("讀取失敗");
                    System.exit(1);
                }

            }
        }).start();

    }

    public static void main(String args[]) {
        try {
            inputStream.connect(outputStream);  //連線
        } catch (IOException e) {
            System.out.println("連線失敗");
            System.exit(1);
        }
        send();
        receive();


    }

}

注意:從上面的執行結果可以看出,緩衝區最多可以寫入1024個位元組的資料,所以在緩衝區滿了之後上面的send程式就會堵塞等待緩衝區空閒,如果recieve程式不繼續讀取資料了,那麼就會一直出現堵塞

問題

  • 寫執行緒正在往緩衝區寫資料的時候,但是此時的讀執行緒的結束讀取,那麼此時的寫執行緒的管道就會發生IOException異常,可以將上面receive程式中的while(true)去掉就可以清楚的看出
  • 讀執行緒正在從緩衝區讀資料的時候,但是此時的寫執行緒的管道已經結束了,此時就會引起讀執行緒的管道發生IOException異常,將上面的send程式中的while(true)去掉就可以實現這個問題
  • 必須是啟用多執行緒才能實現管道之間的讀寫,否則會出現堵塞現象,因為這裡的PipeOutputStream每次向緩衝區寫入的位元組數最大是1024,如果不及時的減少緩衝區的資料量就會出現堵塞

解決方法

  • 後續更新中..........

參考文章

相關文章