Java基礎—IO小結(二)緩衝流與其它流的使用
一、緩衝流的使用
每個位元組流都有對應的緩衝流:
BufferedInputStream / BufferedOutputStream
構造器:
方法摘要與對應節點流類似
使用緩衝流實現檔案複製:實際中也是;其中流的關閉只需要關閉緩衝流,內部巢狀的位元組流會自動關閉。
@Test public void testBuffered1() { // 同樣需要先關聯檔案,注意文字使用Reader Writer,非文字使用fis fos File file1 = new File("D:\\test\\1.jpg"); File file2= new File("D:\\test\\2.jpg"); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { // 建立節點流 FileInputStream fis = new FileInputStream(file1); FileOutputStream fos = new FileOutputStream(file2); // 將節點流包裝為緩衝流 bis = newBufferedInputStream(fis); bos = new BufferedOutputStream(fos); // 準備緩衝的陣列 byte[] bytes = new byte[20]; int len; while ((len = bis.read(bytes)) != -1) { bos.write(bytes, 0, len); // 寫完後將最後的進行重新整理一下 bos.flush(); } }catch (IOException e) { e.printStackTrace(); } finally { // 關閉流,注意流的關閉順序,直接關閉緩衝流時,會自動先關閉對應節點流 if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
BufferedReader與BufferedWriter的使用也是與對應節點流類似
演示獨有的readLine方法:
@Test public void testBufferedReader() { File file1 = new File("D:\\test\\hello.txt"); BufferedReader br = null; try { FileReader fr = new FileReader(file1); br = new BufferedReader(fr); // 使用br獨有的讀行的操作 String s = null; while ((s = br.readLine()) != null) { System.out.println(s); } } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } }
// 注意,讀取doc文件需要使用位元組流(即使文件全部是文字組成,doc也已經不是純文字檔案了)
二、轉換流的使用
InputStreamReader / OutputStreamWriter
JDK中的介紹如下:需要分清編碼與解碼的過程
InputStreamReader 是位元組流通向字元流的橋樑:它使用指定的 charset 讀取位元組並將其解碼為字元。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺預設的字符集。 每次呼叫 InputStreamReader 中的一個 read() 方法都會導致從底層輸入流讀取一個或多個位元組。要啟用從位元組到字元的有效轉換,可以提前從底層流讀取更多的位元組,使其超過滿足當前讀取操作所需的位元組。 為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader。例如: BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); OutputStreamWriter 是字元流通向位元組流的橋樑:可使用指定的 charset 將要寫入流中的字元編碼成位元組。它使用的字符集可以由名稱指定或顯式給定,否則將接受平臺預設的字符集。 每次呼叫 write() 方法都會導致在給定字元(或字符集)上呼叫編碼轉換器。在寫入底層輸出流之前,得到的這些位元組將在緩衝區中累積。可以指定此緩衝區的大小,不過,預設的緩衝區對多數用途來說已足夠大。注意,傳遞給 write() 方法的字元沒有緩衝。 為了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以避免頻繁呼叫轉換器。例如: Writer out = new BufferedWriter(new OutputStreamWriter(System.out)); 代理對 是一個字元,它由兩個 char 值序列表示:高 代理項的範圍為 '\uD800' 到 '\uDBFF',後跟範圍為 '\uDC00' 到 '\uDFFF' 的低 代理項。 錯誤代理元素 指的是後面不跟低代理項的高代理項,或前面沒有高代理項的低代理項。 此類總是使用字符集的預設替代序列 替代錯誤代理元素和不可對映的字元序列。如果需要更多地控制編碼過程,則應該使用 CharsetEncoder 類。
解碼,解成我們能夠看得懂的,也就是解成字串
簡單示例如下:(不是特別重要,不作特別介紹這裡)
@Test public void test1() { File file = new File("D:\\test\\hello.txt"); // 異常處理暫略 FileInputStream fis = new FileInputStream(file); // 位元組流到字元流的解碼 InputStreamReader isr = new InputStreamReader(fis, "GBK"); BufferedReader br = new BufferedReader(isr); String s; // 緩衝流的操作略去 }
三、標準輸入輸出流
也就是我們常見的Syetem.out/in
接收使用者輸入使用示例:
@Test public void test1() { BufferedReader br = null; try { InputStream in = System.in; // 轉換成字元流 InputStreamReader isr = new InputStreamReader(in); br = new BufferedReader(isr); String s; while (true) { System.out.println("請輸入字串:"); s = br.readLine(); if ("exit".equalsIgnoreCase(s)) { break; } String s1 = s.toUpperCase(); System.out.println(s1); } } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } }
四、其它流
1.列印流
列印流都是輸出流,所以分為兩個:位元組列印流和字元列印流
像我們常用的Sytem.out返回的就是一個列印流
關於列印流的資訊,請參見 酒香逢 的隨筆:http://www.cnblogs.com/fnz0/p/5423201.html
2.資料流
用來處理基本資料型別(包括String等)
資料流請參見:http://baihe747.iteye.com/blog/2072146
3.物件流
推薦的序列化與反序列工具是hutool的ObjectUtil的相關方法!
序列化:
序列化一個類的示例:(必須實現相關介面,並且屬性也需要實現Serializable介面)——ObjectOutputStream
@Test public void test1() { // 物件 Person p1 = new Person("小明", 18); Person p2 = new Person("小紅", 23); ObjectOutputStream oos = null; try { // 物件流 FileOutputStream fos = new FileOutputStream(new File("person.txt")); oos = new ObjectOutputStream(fos); oos.writeObject(p1); oos.writeObject(p2); } catch (IOException e) { e.printStackTrace(); } finally { if (oos != null) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class Person implements Serializable{ String name; Integer age; public Person(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
應當加上版本號宣告:
class Person implements Serializable{ private static final long serialVersionUID = 1L;
結果:
反序列化:——ObjectInputStream
@Test public void test2() { ObjectInputStream ois = null; try { FileInputStream fis = new FileInputStream(new File("person.txt")); ois = new ObjectInputStream(fis); // 反序列化到記憶體中了 Person p1 = (Person) ois.readObject(); System.out.println("p1 = " + p1); Person p2 = (Person) ois.readObject(); System.out.println("p2 = " + p2); } catch (Exception e) { e.printStackTrace(); } finally { if (ois != null) { try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
結果:
當然,除了上述的檔案流,我們還可以進行byte[]陣列流的序列化與反序列化,相關的工具類,推薦如下:
package cn.itcast_03_netty.sendobject.utils; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class ByteObjConverter { /** * 使用IO的inputstream流將byte[]轉換為object * @param bytes * @return */ public static Object byteToObject(byte[] bytes) { Object obj = null; ByteArrayInputStream bi = new ByteArrayInputStream(bytes); ObjectInputStream oi = null; try { oi = new ObjectInputStream(bi); obj = oi.readObject(); } catch (Exception e) { e.printStackTrace(); } finally { try { bi.close(); } catch (IOException e) { e.printStackTrace(); } try { oi.close(); } catch (IOException e) { e.printStackTrace(); } } return obj; } /** * 使用IO的outputstream流將object轉換為byte[] * @param bytes * @return */ public static byte[] objectToByte(Object obj) { byte[] bytes = null; ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = null; try { oo = new ObjectOutputStream(bo); oo.writeObject(obj); bytes = bo.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { bo.close(); } catch (IOException e) { e.printStackTrace(); } try { oo.close(); } catch (IOException e) { e.printStackTrace(); } } return bytes; } }
4.隨機存取流
可以解決之前不能追加檔案內容,只能覆蓋的情況