1. 程式人生 > >Java基礎—IO小結(二)緩衝流與其它流的使用

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 = new
BufferedInputStream(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.隨機存取流

    可以解決之前不能追加檔案內容,只能覆蓋的情況