# Java 串接 I/O 串流 >處理 I/O 的程式,很少使用單一串流物件完成;經常將多個串流物件組成「串接(chain)」,藉由不同的串流物件提供不同的功能,一起完成。 ### 常用的串接類別 | 功能 | 位元串流 (Byte Stream) | 字元串流 (Character Stream) | | - | - | - | | Buffering (緩衝) | BufferedInputStream / BufferedOutputStream| BufferedReader / BufferedWriter | | Filtering (過濾) | FilterInputStream / FilterOutputStream | FilterReader / FilterWriter | | Conversion (位元轉字元) || InputStreamReader / OutputStreamWriter | | Object serialization (物件序列化) | ObjectInputStream / ObjectOutputStream || | Data conversion (資料型態轉換) | DataInputStream / DataOutputStream || | Counting (計算行數) | LineNubmerInputStream | LineNumberReader | | Printing (列印) | PrintStream | PrintWriter | ## 串流串接範例 ### 兩個串流類別 >使用 FileInputStream 將資料讀出,然後加入 BufferedInputStream 增加緩衝功能(避免 I/O 忙碌)再進入程式。 ```graphviz digraph dfd{ rankdir=LR; node[shape=record]; subgraph hd { source [label="資料來源" shape=box]; } subgraph cluster_memory { label="Java"; input1 [label="FileInputStream"]; input2 [label="BufferedInputStream"] method [label="程式" shape=Mrecord]; } source -> input1 input1 -> input2 input2 -> method } ``` ### 三個串流類別 >若再加入 DataInputStream,則資料可以被轉換成不同型態(int, double...),再進入程式。 ```graphviz digraph dfd2{ rankdir=LR; node[shape=record]; subgraph hd { source [label="資料來源" shape=box]; } subgraph cluster_memory { label="Java"; input1 [label="FileInputStream"]; input2 [label="BufferedInputStream"]; input3 [label="DataInputStream"]; method [label="程式" shape=Mrecord]; } source -> input1 input1 -> input2 input2 -> input3 input3 -> method } ``` ### 範例程式 ```java= public class CopyBufferedStream { public static void main(String[] args) { String source = "source.txt"; String target = "target.txt"; try (Reader fr = new FileReader(source); BufferedReader br = new BufferedReader(fr); Writer fw = new FileWriter(target); BufferedWriter bw = new BufferedWriter(fw) ) { String line = null; while ((line = br.readLine()) != null) { bw.write(line); bw.newLine(); } } catch (IOException e) { e.printStackTrace(); } } } ``` ### 範例程式說明 | 行號 | 內容 | | - | - | | 6 | 宣告 BufferedReader 裝飾 FileReader | | 8 | 宣告 BufferedWriter 裝飾 FileWriter | | 10 | BufferedReader 每次讀一行(內容+換行符號),**內容**指派給變數 line | | 11 | BufferedReader 逐行寫出資料| | 12 | line 之中無換行符號,所以呼叫 newLine()方法 | ## Channel I/O > JDK 1.4 導入 Channel,Channel 有通道、頻道的意思,可以指兩個設備之間傳送資訊所經過的通路或連接。 > 屬於 java.nio 套件。功能是不需要以迴圈讀寫內容,可以讀大量讀寫位元和字元。 ### 範例程式 ```java= public class CopyByteChannel { public static void main(String[] args) { String source = "source.txt"; String target = "target.txt"; try (FileInputStream fis = new FileInputStream(source); FileChannel fisc = fis.getChannel(); FileOutputStream fos = new FileOutputStream(target); FileChannel fosc = fos.getChannel() ) { ByteBuffer buff = ByteBuffer.allocate((int) fisc.size()); fisc.read(buff); buff.position(0); fosc.write(buff); } catch (IOException e) { e.printStackTrace(); } } } ``` ### 範例程式說明 | 行號 | 內容 | | - | - | | 9 | 建立 source 檔大小的 ByteBuffer 物件 | | 10 | 將實體檔案一次全數讀入 ByteBuffer 物件 | | 11 | 將 ByteBuffer 裡的標示位置移到最前面 | | 12 | FileChannel 接收 ByteBuffer 裡的資料,直接輸出檔案 | #### 備註 > FileChannel 的 read() 和 write() 方法都是透過 ByteBuffer 物件一次完成,所以不用迴圈分批處理。 ###### tags: `Java`, `Java I/O`, `Java Channel`