IO流、緩衝字節流、緩衝字符流、轉換流、序列化和反序列化【總結】

一、緩衝字節流
    1.緩衝字節輸出流
        BufferedOutputStream(OutputStream);
        示例代碼:
            public class Demo01BufferedOutputStream {
                public static void main(String[] args) throws IOException {
                    //2.創建BufferedOutputStream對象,構造方法中傳遞FileOutputStream對象,提高FileOutputStream對象效率
                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("10_IO\\a.txt"));
                    //3.使用BufferedOutputStream對象中的方法write,把數據寫入到內部緩衝區中
                    bos.write("我把數據寫入到內部緩衝區中".getBytes());
                    //4.使用BufferedOutputStream對象中的方法flush,把內部緩衝區中的數據,刷新到文件中
                    bos.flush();
                    //5.釋放資源(會先調用flush方法刷新數據,第4部可以省略)
                    bos.close();
                }
            }
    注意事項:
        1.BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("F:\\Test\\out.txt"));  ("...",true)  
            FileOutputStream fos = new FileOutputStream("f:\\Test\\4.txt");   ("...",true)  
            創建字節輸出流或者緩衝字節輸出流,不指定文件續寫那麼會創建一個新的文件直接覆蓋原文件,(也就是清空文件)
        2.在使用字節流或者字符流讀取的時候,創建數組,將內容讀取到數組中的時候,最後在輸出或者寫入文件(文件的複製) 
            的時候要注意
            fos.write(bytes,0,index);
            sout(new String(bytes,0,index))   //將字符數組轉換爲字符串   1
            sout(String.valueOf(bytes,0,,index))    //.... 2




    2.緩衝字節輸入流
        BufferedInputStream(InputStream);
        示例代碼:
            public class Demo02BufferedInputStream {
                public static void main(String[] args) throws IOException {
                    //1.創建FileInputStream對象,構造方法中綁定要讀取的數據源
                    FileInputStream fis = new FileInputStream("10_IO\\a.txt");
                    //2.創建BufferedInputStream對象,構造方法中傳遞FileInputStream對象,提高FileInputStream對象的讀取效率
                    BufferedInputStream bis = new BufferedInputStream(fis);
                    //3.使用BufferedInputStream對象中的方法read,讀取文件
                    //int read()從輸入流中讀取數據的下一個字節。
                    /*int len = 0;//記錄每次讀取到的字節
                    while((len = bis.read())!=-1){
                        System.out.println(len);
                    }*/

                    //int read(byte[] b) 從輸入流中讀取一定數量的字節,並將其存儲在緩衝區數組 b 中。
                    byte[] bytes =new byte[1024];//存儲每次讀取的數據
                    int len = 0; //記錄每次讀取的有效字節個數
                    while((len = bis.read(bytes))!=-1){
                        System.out.println(new String(bytes,0,len));
                    }

                    //4.釋放資源
                    bis.close();
                }
            }

    3.測試一下字節流複製文件的效率
        通過測試,緩衝流配合小數組的形式速度最快
        //第四種:緩衝字節流一次讀寫一個字節數組
        private static void demo04() throws IOException{
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\視頻\\頸椎操.flv"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\dest\\頸椎操.flv"));

            byte[] arr = new byte[1024];
            int len;
            while((len = bis.read(arr)) != -1) {
                bos.write(arr,0,len);
            }

            bis.close();
            bos.close();
        }


二、緩衝字符流
    1.緩衝字符輸出流
        BufferedWriter(Writer);
        特殊方法:
            newLine();           寫入一個和系統匹配的換行符
        示例代碼:
            public class Demo03BufferedWriter {
                public static void main(String[] args) throws IOException {
                    //System.out.println();
                    //1.創建字符緩衝輸出流對象,構造方法中傳遞字符輸出流
                    BufferedWriter bw = new BufferedWriter(new FileWriter("10_IO\\c.txt"));
                    //2.調用字符緩衝輸出流中的方法write,把數據寫入到內存緩衝區中
                    for (int i = 0; i <10 ; i++) {
                        bw.write("傳智播客");
                        //bw.write("\r\n");
                        bw.newLine();
                    }
                    //3.調用字符緩衝輸出流中的方法flush,把內存緩衝區中的數據,刷新到文件中
                    bw.flush();
                    //4.釋放資源
                    bw.close();
                }
            }

    2.緩衝字符輸入流
        BufferedReader(Reader);
        特殊方法:
            String readLine();                  一次讀取一整行
        示例代碼:
            public class Demo04BufferedReader {
                public static void main(String[] args) throws IOException {
                    //1.創建字符緩衝輸入流對象,構造方法中傳遞字符輸入流
                    BufferedReader br = new BufferedReader(new FileReader("10_IO\\c.txt"));

                    //2.使用字符緩衝輸入流對象中的方法read/readLine讀取文本
                    /*
                        發下以上讀取是一個重複的過程,所以可以使用循環優化
                        不知道文件中有多少行數據,所以使用while循環
                        while的結束條件,讀取到null結束
                     */
                    String line;
                    while((line = br.readLine())!=null){
                        System.out.println(line);
                    }

                    //3.釋放資源
                    br.close();
                }
            }

    3.緩衝字符流練習
        /*
            一、根據需求、完成代碼
            1.項目根目錄下建立文件: user.txt,文件中存放用戶名和登錄密碼,格式:用戶名,密碼,如:aaa,123;
            2. user.txt文件中初始存放的用戶信息有如下:
                jack,123
                rose,123
                tom,123
            3.要求完成如下功能:
              程序運行時:控制檯提示用戶輸入註冊的用戶名和密碼;
               驗證鍵盤錄入的用戶名跟user.txt中已註冊的用戶名是否重複:
               是:控制檯提示:用戶名已存在
               否:將鍵盤錄入的用戶名及密碼寫入user.txt文件,並在控制檯提示:註冊成功
         */
        public class Day09_HomeWork01 {
            public static void main(String[] args) throws IOException {
                Scanner sc = new Scanner(System.in);
                System.out.println("請輸入用戶名:");
                String username = sc.nextLine();
                System.out.println("請輸入密碼:");
                String password = sc.nextLine();

                boolean flag = false;

                BufferedReader br = new BufferedReader(new FileReader("my01-code\\user.txt"));
                String line;
                while((line = br.readLine()) != null) {
                    String[] arr = line.split(",");
                    if(arr[0].equals(username)) {
                        flag = true;
                    }
                }

                //對標識做判斷
                if(flag) {
                    System.out.println("用戶名已存在");
                }else {
                    //將鍵盤錄入的用戶名及密碼寫入user.txt文件,並在控制檯提示:註冊成功
                    BufferedWriter bw = new BufferedWriter(new FileWriter("my01-code\\user.txt",true));
                    bw.write(username + "," + password);
                    bw.newLine();
                    bw.close();
                    System.out.println("註冊成功");
                }

                br.close();

            }
        }
        //方法二
        public class work {
            public static void main(String[] args) throws IOException {

                BufferedReader bf = new BufferedReader(new FileReader("user.txt"));
                String line = null;

                LinkedHashSet<String> hash = new LinkedHashSet<>();
                while ((line = bf.readLine()) != null) {
                    String[] split = line.split(",");   //通過正則表達式根據 , 規則切割
                    hash.add(split[0]);    //切割後的split[0]是用戶名,存入set集合中
                }

                Scanner sc = new Scanner(System.in);
                String inputStr = sc.next();    //用戶輸入的字符串
                String spiltInputStr[]=inputStr.split(",");
                if (hash.add(spiltInputStr[0]) == false)   //根據HashSet集合不能存儲元素,當存入重複的元素時返回false,此種情況爲存入了重複元素
                {
                    System.out.println("用戶名存在");
                } else {     //當集合裏面有沒此用戶名時,創建字符輸入流並且設爲續寫
                    BufferedWriter bw = new BufferedWriter(new FileWriter("user.txt",true));
                    bw.newLine();   //換行
                    bw.write(inputStr);
                    System.out.println("註冊成功");
                    bw.close();
                }
                bf.close();
            }
        }


    1注意事項:  因爲字符流在讀寫文件的編碼格式不一致的時候就會出現亂碼問題,那麼我們就可以通過
                轉換輸入流InputStreamReader和轉換輸出流OutputStreamReader去指定讀或者寫文件的編碼格式


三、轉換流
    1.編碼表
        ASCII碼錶:美國的碼錶,支持一些字母、數字等等
        ISO-8859-1碼錶:支持歐洲各國家的碼錶
        GB2312:早先的中文的碼錶
        GBK碼錶:目前廣泛使用的碼錶
        GB18030碼錶:最新的中文碼錶
        Unicode碼錶:萬國碼,各個國家的碼錶都包含在內

    2.轉換輸出流
        OutputStreamWriter(OutputStream os,String chasetName)      字符流通向字節流的橋樑
        使用轉換輸出流對象寫出指定格式的文件
        public class Demo02OutputStreamWriter {
            public static void main(String[] args) throws IOException {
                //write_utf_8();
                write_gbk();
            }

            /*
               使用轉換流OutputStreamWriter寫GBK格式的文件
            */
            private static void write_gbk() throws IOException {
                //1.創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱
                OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\gbk.txt"),"GBK");
                //2.使用OutputStreamWriter對象中的方法write,把字符轉換爲字節存儲緩衝區中(編碼)
                osw.write("你好");
                //3.使用OutputStreamWriter對象中的方法flush,把內存緩衝區中的字節刷新到文件中(使用字節流寫字節的過程)
                osw.flush();
                //4.釋放資源
                osw.close();
            }

            /*
                使用轉換流OutputStreamWriter寫UTF-8格式的文件
             */
            private static void write_utf_8() throws IOException {
                //1.創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱
                //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\utf_8.txt"),"utf-8");
                OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\utf_8.txt"));//不指定默認使用UTF-8
                //2.使用OutputStreamWriter對象中的方法write,把字符轉換爲字節存儲緩衝區中(編碼)
                osw.write("你好");
                //3.使用OutputStreamWriter對象中的方法flush,把內存緩衝區中的字節刷新到文件中(使用字節流寫字節的過程)
                osw.flush();
                //4.釋放資源
                osw.close();
            }
        }

    3.轉換輸入流
        InputStreamReader(InputStream is,String chasetName);      字節流通向字符流的橋樑
        使用轉換入流讀取指定編碼格式的文件
            public class Demo03InputStreamReader {
                public static void main(String[] args) throws IOException {
                    //read_utf_8();
                    read_gbk();
                }


                /*
                    使用InputStreamReader讀取GBK格式的文件
                 */
                private static void read_gbk() throws IOException {
                    //1.創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱
                    //InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\gbk.txt"),"UTF-8");//???
                    InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\gbk.txt"),"GBK");//你好

                    //2.使用InputStreamReader對象中的方法read讀取文件
                    int len = 0;
                    while((len = isr.read())!=-1){
                        System.out.println((char)len);
                    }
                    //3.釋放資源
                    isr.close();
                }

                /*
                    使用InputStreamReader讀取UTF-8格式的文件
                 */
                private static void read_utf_8() throws IOException {
                    //1.創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱
                    //InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\utf_8.txt"),"UTF-8");
                    InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\utf_8.txt"));//不指定默認使用UTF-8
                    //2.使用InputStreamReader對象中的方法read讀取文件
                    int len = 0;
                    while((len = isr.read())!=-1){
                        System.out.println((char)len);
                    }
                    //3.釋放資源
                    isr.close();
                }
            }

    4.使用轉換流讀取gbk格式文件,並以utf-8格式寫出到另外一個文件中
        public class Demo04Test {
            public static void main(String[] args) throws IOException {
                //1.創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱GBK
                InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\我是GBK格式的文本.txt"),"GBK");
                //2.創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱UTF-8
                OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\我是utf_8格式的文件.txt"),"UTF-8");
                //3.使用InputStreamReader對象中的方法read讀取文件
                int len = 0;
                while((len = isr.read())!=-1){
                    //4.使用OutputStreamWriter對象中的方法write,把讀取的數據寫入到文件中
                    osw.write(len);
                }
                //5.釋放資源
                osw.close();
                isr.close();
            }
        }

四、序列化流
    1.什麼是序列化和反序列化
        序列化:將對象寫出
        反序列化:將對象讀回來
    2.序列化流,寫出對象的流
        構造方法:
            ObjectOutputStream(OutputStream);
        成員方法:
            writeObject(Object obj);
        示例代碼:
            //要求被寫出的對象必須實現 Serializable接口
            public class Demo01ObjectOutputStream {
                public static void main(String[] args) throws IOException {
                    //1.創建ObjectOutputStream對象,構造方法中傳遞字節輸出流
                    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("10_IO\\person.txt"));
                    //2.使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中
                    oos.writeObject(new Person("小美女",18));
                    //3.釋放資源
                    oos.close();
                }
            }
    3.反序列化流,讀取對象的流
        構造方法:
            ObjectInputStream(InputStream in);
        成員方法:
            Object readObject();
        示例代碼:
            public class Demo02ObjectInputStream {
                public static void main(String[] args) throws IOException, ClassNotFoundException {
                    //1.創建ObjectInputStream對象,構造方法中傳遞字節輸入流
                    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10_IO\\person.txt"));
                    //2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件
                    Object o = ois.readObject();
                    //3.釋放資源
                    ois.close();
                    //4.使用讀取出來的對象(打印)
                    System.out.println(o);
                    Person p = (Person)o;
                    System.out.println(p.getName()+p.getAge());
                }
            }

    4.瞬態關鍵字:transient
        作用:被該關鍵字修飾的變量,不參與序列化和反序列化

    5.使用序列化流的常見的異常和解決方式
        A: NotSerializableException  
            出現的原因:被序列化的類沒有實現 Serializable 接口
            解決的方案:讓該類實現 Serializable 接口
        B: InvalidClassException
            出現的原因:序列化的id不匹配
            解決的方案:生成一個固定的序列化id號即可
        C: EOFException
            出現的原因:讀取到序列化文件末尾的時候,因爲這裏面的讀取方法和字節流字符流裏面的不一樣,
                        不是返回null或者-1,而是拋出異常
            解決的方案:將要寫出的多個對象,保存到一個容器中。將整個容器對象進行寫出。那麼在讀取的時候,
                        只需要讀一次即可

    6.序列化練習-一次寫出和讀取多個對象
        public class Demo03Test {
            public static void main(String[] args) throws IOException, ClassNotFoundException {
                //1.定義一個存儲Person對象的ArrayList集合
                ArrayList<Person> list = new ArrayList<>();
                //2.往ArrayList集合中存儲Person對象
                list.add(new Person("張三",18));
                list.add(new Person("李四",19));
                list.add(new Person("王五",20));
                //3.創建一個序列化流ObjectOutputStream對象
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("10_IO\\list.txt"));
                //4.使用ObjectOutputStream對象中的方法writeObject,對集合進行序列化
                oos.writeObject(list);
                oos.close();

                //5.創建一個反序列化ObjectInputStream對象
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10_IO\\list.txt"));
                //6.使用ObjectInputStream對象中的方法readObject讀取文件中保存的集合
                Object o = ois.readObject();
                //7.把Object類型的集合轉換爲ArrayList類型
                ArrayList<Person> list2 = (ArrayList<Person>)o;
                //8.遍歷ArrayList集合
                for (Person p : list2) {
                    System.out.println(p);
                }
                //9.釋放資源
                ois.close();
            }
        }

五、打印流
    1.PrintStream類
        示例代碼:直接寫出數據到文件中
            public class Demo01PrintStream {
                public static void main(String[] args) throws FileNotFoundException {
                    //System.out.println("HelloWorld");

                    //創建打印流PrintStream對象,構造方法中綁定要輸出的目的地
                    PrintStream ps = new PrintStream("10_IO\\print.txt");
                    //如果使用繼承自父類的write方法寫數據,那麼查看數據的時候會查詢編碼表 97->a
                    ps.write(97);
                    //如果使用自己特有的方法print/println方法寫數據,寫的數據原樣輸出 97->97
                    ps.println(97);
                    ps.println(8.8);
                    ps.println('a');
                    ps.println("HelloWorld");
                    ps.println(true);

                    //釋放資源
                    ps.close();
                }
            }

        示例代碼:改變輸出語句,將內容輸出到文件中
            public class Demo02PrintStream {
                public static void main(String[] args) throws FileNotFoundException {
                    System.out.println("我是在控制檯輸出");

                    PrintStream ps = new PrintStream("10_IO\\目的地是打印流.txt");
                    System.setOut(ps);//把輸出語句的目的地改變爲打印流的目的地
                    System.out.println("我在打印流的目的地中輸出");

                    ps.close();
                }
            }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章