# Java I/O >Java 將 I/O (input/output),亦即輸入/輸出的概念,以 stream (水流或串流)的抽象概念表達 ```graphviz digraph dfd{ rankdir=LR; node[shape=record]; subgraph hd { source [label="資料來源" shape=box]; target [label="資料目的" shape=box]; } subgraph cluster_memory { label="Java"; input [label="輸入流"]; output [label="輸出流"]; method [label="程式" shape=Mrecord]; } source -> input input -> method method -> output output -> target } ``` ### Stream 如水流具有方向性: 1. 若方向是流入 Java 程式,則稱為「輸入(input)流」或「來源(source)」 2. 若方向是流出 Java 程式,則稱為「輸出(output)流」或「目的(sink)」 ### 流動的內容也分兩類: 1. 位元(byte) 2. 字元(character) ## 處理串流的類別 根據串流內的資料分類,加上流動方向,處理類別可以區分成四大類,這些都是抽象類別: |方向|位元(byte)| 字元(character) | |-|-|-| |輸入流|InputStream|Reader| |輸出流|OutputStream|Writer| ## InputStream 類別 ### 基本方法 * int read() 每次讀取1個 byte。 * int read(byte[] buffer) 每次讀取1個 byte[] 至 buffer 中,回傳讀取長度。 * int read(byte[] buffer, int offset, int length) 每次讀取1個 byte[],指定偏移量(offset)和讀取長度(length)。 * void close() 關閉 stream 。 * int available() 有多少 bytes 可供讀取。 * long skip(long n) 讀取時掠過 n 個 bytes。 ### 其他方法 * boolean markSupported() * void mark(int readlimit) * void reset() push-back 操作,合併用於改變檔案中的讀取位置,特別是回到過去某個指定的讀取位置。 ## OutputStream 類別 ### 基本方法 * void write(int b) 將 b 寫入 OutputStream。 * void write(byte[] buffer) 將 buffer 寫入 OutputStream。 * void write(byte[] buffer, int offset, int length) 將 buffer 寫入 OutputStream,且指定偏移量(offset)和長度(length)。 * void close() 關閉 stream 。 * int flush() 強制將 OutputStream 中的資料寫入目的。 ## 位元串流範例 ### 範例程式 ```java= public class CopyByteStream { public static void main(String[] args) { String source = "source.txt"; String target = "target.txt"; byte[] bytes = new byte[128]; int bLen = bytes.length; try (InputStream fis = new FileInputStream(source); OutputStream fos = new FileOutputStream(target)) { System.out.println("Will copy bytes:" + fis.available()); int read; while ((read = fis.read(bytes)) != -1) { if (read < bLen) { fos.write(bytes, 0, read); } else { fos.write(bytes); } } } catch (IOException e) { e.printStackTrace(); } } } ``` ### 範例程式說明 |行號|內容| |-|-| |10|宣告每次讀取長度 read| |11|每次都讀一個 byte[128],回傳 -1 表示讀完| |12|讀入長度不滿 byte[128] 時| |13|寫入 bytes[0:read]| ## Reader 類別 ### 基本方法 * int read() 每次讀取1個 char。 * int read(char[] buffer) 每次讀取1個 char[] 至 buffer 中,回傳讀取長度。 * int read(byte[] buffer, int offset, int length) 每次讀取1個 char[],指定偏移量(offset)和讀取長度(length)。 * void close() 關閉 stream 。 * boolean ready() 確認 stream 是否已準備好進行資料讀取。 * long skip(long n) 讀取時掠過 n 個 chars。 ### 其他方法 * boolean markSupported() * void mark(int readAheadLimit) * void reset() push-back 操作,合併用於改變檔案中的讀取位置,特別是回到過去某個指定的讀取位置。 ## Writer 類別 ### 基本方法 * void write(int c) 將 c 寫入 Writer。 * void write(char[] buffer) 將 buffer 寫入 Writer。 * void write(byte[] buffer, int offset, int length) 將 buffer 寫入 Writer,且指定偏移量(offset)和長度(length)。 * void close() 關閉 stream 。 * int flush() 強制將 Writer 中的資料寫入目的。 ## 字元串流範例 ### 範例程式 ```java= public class CopyCharStream { public static void main(String[] args) { String source = "source.txt"; String target = "target.txt"; char[] chars = new char[128]; int cLen = chars.length; try (Reader fr = new FileReader(source); Writer fw = new FileWriter(target)) { int read; while ((read = fr.read(chars)) != -1) { if (read < cLen) { fw.write(chars, 0, read); } else { fw.write(chars); } } } catch (IOException e) { e.printStackTrace(); } } } ``` ### 範例程式說明 |行號|內容| |-|-| |9|宣告每次讀取長度 read| |10|每次都讀一個 char[128],回傳 -1 表示讀完| |11|讀入長度不滿 char[128] 時| |12|寫入 chars[0:read]| ###### tags: `Java`, `Java I/O`