天天看點

十、Java IO流十、Java IO流

文章目錄

  • 十、Java IO流
    • 1.File類
      • 1.1File類概述和構造方法【應用】
      • 1.2File類建立功能【應用】
      • 1.3File類判斷和擷取功能【應用】
      • 1.4File類删除功能【應用】
    • 2.遞歸
      • 2.1遞歸【應用】
      • 2.2遞歸求階乘【應用】
      • 2.3遞歸周遊目錄【應用】
    • 3.IO流
      • 3.1 IO流概述和分類【了解】
      • 3.2位元組流寫資料【應用】
      • 3.3位元組流寫資料的三種方式【應用】
      • 3.4位元組流寫資料的兩個小問題【應用】
      • 3.5位元組流寫資料加異常處理【應用】
      • 3.6位元組流讀資料(一次讀一個位元組資料)【應用】
      • 3.7位元組流複制文本檔案【應用】
      • 3.8位元組流讀資料(一次讀一個位元組數組資料)【應用】
      • 3.9位元組流複制圖檔【應用】
    • 4.位元組緩沖流
      • 4.1位元組緩沖流構造方法【應用】
      • 4.2位元組流複制視訊【應用】
    • 5.字元流
      • 5.1為什麼會出現字元流【了解】
      • 5.2編碼表【了解】
      • 5.3字元串中的編碼解碼問題【應用】
      • 5.4字元流中的編碼解碼問題【應用】
      • 5.5字元流寫資料的5種方式【應用】
      • 5.6字元流讀資料的2種方式【應用】
      • 5.7字元流複制Java檔案【應用】
      • 5.8字元流複制Java檔案改進版【應用】
      • 5.9字元緩沖流【應用】
      • 5.10字元緩沖流複制Java檔案【應用】
      • 5.11字元緩沖流特有功能【應用】
      • 5.12字元緩沖流特有功能複制Java檔案【應用】
      • 5.13IO流小結【了解】
      • 6練習案例
      • 6.1集合到檔案【應用】
      • 6.2檔案到集合【應用】
      • 6.3點名器【應用】
      • 6.4集合到檔案改進版【應用】
      • 6.5檔案到集合改進版【應用】
    • 7.IO流案例
      • 7.1集合到檔案資料排序改進版【應用】
        • 7.1.1案例需求
        • 7.1.2分析步驟
        • 1.1.3代碼實作
      • 7.2複制單級檔案夾【應用】
        • 7.2.1案例需求
        • 7.2.2分析步驟
        • 7.2.3代碼實作
      • 7.3複制多級檔案夾【應用】
        • 7.3.1案例需求
        • 7.3.2分析步驟
        • 7.3.3代碼實作
      • 7.4複制檔案的異常處理【應用】
        • 7.4.1基本做法
        • 7.4.2JDK7版本改進
        • 7.4.3JDK9版本改進
    • 8.IO特殊操作流
      • 8.1标準輸入流【應用】
      • 8.2标準輸出流【應用】
      • 8.3位元組列印流【應用】
      • 8.4字元列印流【應用】
      • 8.5複制Java檔案列印流改進版【應用】
      • 8.6對象序列化流【應用】
      • 8.7對象反序列化流【應用】
      • 8.8serialVersionUID&transient【應用】
    • 9.Properties集合
      • 9.1Properties作為Map集合的使用【應用】
      • 9.2Properties作為Map集合的特有方法【應用】
      • 9.3Properties和IO流相結合的方法【應用】
      • 9.4遊戲次數案例【應用】

十、Java IO流

1.File類

1.1File類概述和構造方法【應用】

  • File類介紹
    • 它是檔案和目錄路徑名的抽象表示
    • 檔案和目錄是可以通過File封裝成對象的
    • 對于File而言,其封裝的并不是一個真正存在的檔案,僅僅是一個路徑名而已。它可以是存在的,也可以是不存在的。将來是要通過具體的操作把這個路徑的内容轉換為具體存在的
  • File類的構造方法
    方法名 說明
    File(String pathname) 通過将給定的路徑名字元串轉換為抽象路徑名來建立新的 File執行個體
    File(String parent, String child) 從父路徑名字元串和子路徑名字元串建立新的 File執行個體
    File(File parent, String child) 從父抽象路徑名和子路徑名字元串建立新的 File執行個體
  • 示例代碼
    public class FileDemo01 {
        public static void main(String[] args) {
            //File(String pathname):通過将給定的路徑名字元串轉換為抽象路徑名來建立新的 File執行個體。
            File f1 = new File("E:\\itcast\\java.txt");
            System.out.println(f1);
    
            //File(String parent, String child):從父路徑名字元串和子路徑名字元串建立新的 File執行個體。
            File f2 = new File("E:\\itcast","java.txt");
            System.out.println(f2);
    
            //File(File parent, String child):從父抽象路徑名和子路徑名字元串建立新的 File執行個體。
            File f3 = new File("E:\\itcast");
            File f4 = new File(f3,"java.txt");
            System.out.println(f4);
        }
    }
               

1.2File類建立功能【應用】

  • 方法分類
    方法名 說明
    public boolean createNewFile() 當具有該名稱的檔案不存在時,建立一個由該抽象路徑名命名的新空檔案
    public boolean mkdir() 建立由此抽象路徑名命名的目錄
    public boolean mkdirs() 建立由此抽象路徑名命名的目錄,包括任何必需但不存在的父目錄
  • 示例代碼
    public class FileDemo02 {
        public static void main(String[] args) throws IOException {
            //需求1:我要在E:\\itcast目錄下建立一個檔案java.txt
            File f1 = new File("E:\\itcast\\java.txt");
            System.out.println(f1.createNewFile());
            System.out.println("--------");
    
            //需求2:我要在E:\\itcast目錄下建立一個目錄JavaSE
            File f2 = new File("E:\\itcast\\JavaSE");
            System.out.println(f2.mkdir());
            System.out.println("--------");
    
            //需求3:我要在E:\\itcast目錄下建立一個多級目錄JavaWEB\\HTML
            File f3 = new File("E:\\itcast\\JavaWEB\\HTML");
    //        System.out.println(f3.mkdir());
            System.out.println(f3.mkdirs());
            System.out.println("--------");
    
            //需求4:我要在E:\\itcast目錄下建立一個檔案javase.txt
            File f4 = new File("E:\\itcast\\javase.txt");
    //        System.out.println(f4.mkdir());
            System.out.println(f4.createNewFile());
        }
    }
               

1.3File類判斷和擷取功能【應用】

  • 判斷功能
    方法名 說明
    public boolean isDirectory() 測試此抽象路徑名表示的File是否為目錄
    public boolean isFile() 測試此抽象路徑名表示的File是否為檔案
    public boolean exists() 測試此抽象路徑名表示的File是否存在
  • 擷取功能
    方法名 說明
    public String getAbsolutePath() 傳回此抽象路徑名的絕對路徑名字元串
    public String getPath() 将此抽象路徑名轉換為路徑名字元串
    public String getName() 傳回由此抽象路徑名表示的檔案或目錄的名稱
    public String[] list() 傳回此抽象路徑名表示的目錄中的檔案和目錄的名稱字元串數組
    public File[] listFiles() 傳回此抽象路徑名表示的目錄中的檔案和目錄的File對象數組
  • 示例代碼
    public class FileDemo04 {
        public static void main(String[] args) {
            //建立一個File對象
            File f = new File("myFile\\java.txt");
    
    //        public boolean isDirectory():測試此抽象路徑名表示的File是否為目錄
    //        public boolean isFile():測試此抽象路徑名表示的File是否為檔案
    //        public boolean exists():測試此抽象路徑名表示的File是否存在
            System.out.println(f.isDirectory());
            System.out.println(f.isFile());
            System.out.println(f.exists());
    
    //        public String getAbsolutePath():傳回此抽象路徑名的絕對路徑名字元串
    //        public String getPath():将此抽象路徑名轉換為路徑名字元串
    //        public String getName():傳回由此抽象路徑名表示的檔案或目錄的名稱
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getPath());
            System.out.println(f.getName());
            System.out.println("--------");
    
    //        public String[] list():傳回此抽象路徑名表示的目錄中的檔案和目錄的名稱字元串數組
    //        public File[] listFiles():傳回此抽象路徑名表示的目錄中的檔案和目錄的File對象數組
            File f2 = new File("E:\\itcast");
    
            String[] strArray = f2.list();
            for(String str : strArray) {
                System.out.println(str);
            }
            System.out.println("--------");
    
            File[] fileArray = f2.listFiles();
            for(File file : fileArray) {
    //            System.out.println(file);
    //            System.out.println(file.getName());
                if(file.isFile()) {
                    System.out.println(file.getName());
                }
            }
        }
    }
               

1.4File類删除功能【應用】

  • 方法分類
    方法名 說明
    public boolean delete() 删除由此抽象路徑名表示的檔案或目錄
  • 示例代碼
    public class FileDemo03 {
        public static void main(String[] args) throws IOException {
    //        File f1 = new File("E:\\itcast\\java.txt");
            //需求1:在目前子產品目錄下建立java.txt檔案
            File f1 = new File("myFile\\java.txt");
    //        System.out.println(f1.createNewFile());
    
            //需求2:删除目前子產品目錄下的java.txt檔案
            System.out.println(f1.delete());
            System.out.println("--------");
    
            //需求3:在目前子產品目錄下建立itcast目錄
            File f2 = new File("myFile\\itcast");
    //        System.out.println(f2.mkdir());
    
            //需求4:删除目前子產品目錄下的itcast目錄
            System.out.println(f2.delete());
            System.out.println("--------");
    
            //需求5:在目前子產品下建立一個目錄itcast,然後在該目錄下建立一個檔案java.txt
            File f3 = new File("myFile\\itcast");
    //        System.out.println(f3.mkdir());
            File f4 = new File("myFile\\itcast\\java.txt");
    //        System.out.println(f4.createNewFile());
    
            //需求6:删除目前子產品下的目錄itcast
            System.out.println(f4.delete());
            System.out.println(f3.delete());
        }
    }
               
  • 絕對路徑和相對路徑的差別
    • 絕對路徑:完整的路徑名,不需要任何其他資訊就可以定位它所表示的檔案。例如:E:\itcast\java.txt
    • 相對路徑:必須使用取自其他路徑名的資訊進行解釋。例如:myFile\java.txt

2.遞歸

2.1遞歸【應用】

  • 遞歸的介紹
    • 以程式設計的角度來看,遞歸指的是方法定義中調用方法本身的現象
    • 把一個複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解
    • 遞歸政策隻需少量的程式就可描述出解題過程所需要的多次重複計算
  • 遞歸的基本使用
    public class DiGuiDemo {
        public static void main(String[] args) {
            //回顧不死神兔問題,求第20個月兔子的對數
            //每個月的兔子對數:1,1,2,3,5,8,...
            int[] arr = new int[20];
    
            arr[0] = 1;
            arr[1] = 1;
    
            for (int i = 2; i < arr.length; i++) {
                arr[i] = arr[i - 1] + arr[i - 2];
            }
            System.out.println(arr[19]);
            System.out.println(f(20));
        }
    
        /*
            遞歸解決問題,首先就是要定義一個方法:
                定義一個方法f(n):表示第n個月的兔子對數
                那麼,第n-1個月的兔子對數該如何表示呢?f(n-1)
                同理,第n-2個月的兔子對數該如何表示呢?f(n-2)
    
            StackOverflowError:當堆棧溢出發生時抛出一個應用程式遞歸太深
         */
        public static int f(int n) {
            if(n==1 || n==2) {
                return 1;
            } else {
                return f(n - 1) + f(n - 2);
            }
        }
    }
               
  • 遞歸的注意事項
    • 遞歸一定要有出口。否則記憶體溢出
    • 遞歸雖然有出口,但是遞歸的次數也不宜過多。否則記憶體溢出

2.2遞歸求階乘【應用】

  • 案例需求

    用遞歸求5的階乘,并把結果在控制台輸出

  • 代碼實作
    public class DiGuiDemo01 {
        public static void main(String[] args) {
            //調用方法
            int result = jc(5);
            //輸出結果
            System.out.println("5的階乘是:" + result);
        }
    
        //定義一個方法,用于遞歸求階乘,參數為一個int類型的變量
        public static int jc(int n) {
            //在方法内部判斷該變量的值是否是1
            if(n == 1) {
                //是:傳回1
                return 1;
            } else {
                //不是:傳回n*(n-1)!
                return n*jc(n-1);
            }
        }
    }
               

2.3遞歸周遊目錄【應用】

  • 案例需求

    給定一個路徑(E:\itcast),通過遞歸完成周遊該目錄下所有内容,并把所有檔案的絕對路徑輸出在控制台

  • 代碼實作
    public class DiGuiDemo02 {
        public static void main(String[] args) {
            //根據給定的路徑建立一個File對象
    //        File srcFile = new File("E:\\itcast");
            File srcFile = new File("E:\\itheima");
    
            //調用方法
            getAllFilePath(srcFile);
        }
    
        //定義一個方法,用于擷取給定目錄下的所有内容,參數為第1步建立的File對象
        public static void getAllFilePath(File srcFile) {
            //擷取給定的File目錄下所有的檔案或者目錄的File數組
            File[] fileArray = srcFile.listFiles();
            //周遊該File數組,得到每一個File對象
            if(fileArray != null) {
                for(File file : fileArray) {
                    //判斷該File對象是否是目錄
                    if(file.isDirectory()) {
                        //是:遞歸調用
                        getAllFilePath(file);
                    } else {
                        //不是:擷取絕對路徑輸出在控制台
                        System.out.println(file.getAbsolutePath());
                    }
                }
            }
        }
    }
               

3.IO流

3.1 IO流概述和分類【了解】

  • IO流介紹
    • IO:輸入/輸出(Input/Output)
    • 流:是一種抽象概念,是對資料傳輸的總稱。也就是說資料在裝置間的傳輸稱為流,流的本質是資料傳輸
    • IO流就是用來處理裝置間資料傳輸問題的。常見的應用:檔案複制;檔案上傳;檔案下載下傳
  • IO流的分類
    • 按照資料的流向
      • 輸入流:讀資料
      • 輸出流:寫資料
    • 按照資料類型來分
      • 位元組流
        • 位元組輸入流
        • 位元組輸出流
      • 字元流
        • 字元輸入流
        • 字元輸出流
  • IO流的使用場景
    • 如果操作的是純文字檔案,優先使用字元流
    • 如果操作的是圖檔、視訊、音頻等二進制檔案。優先使用位元組流
    • 如果不确定檔案類型,優先使用位元組流。位元組流是萬能的流

3.2位元組流寫資料【應用】

  • 位元組流抽象基類
    • InputStream:這個抽象類是表示位元組輸入流的所有類的超類
    • OutputStream:這個抽象類是表示位元組輸出流的所有類的超類
    • 子類名特點:子類名稱都是以其父類名作為子類名的字尾
  • 位元組輸出流
    • FileOutputStream(String name):建立檔案輸出流以指定的名稱寫入檔案
  • 使用位元組輸出流寫資料的步驟
    • 建立位元組輸出流對象(調用系統功能建立了檔案,建立位元組輸出流對象,讓位元組輸出流對象指向檔案)
    • 調用位元組輸出流對象的寫資料方法
    • 釋放資源(關閉此檔案輸出流并釋放與此流相關聯的任何系統資源)
  • 示例代碼
    public class FileOutputStreamDemo01 {
        public static void main(String[] args) throws IOException {
            //建立位元組輸出流對象
            //FileOutputStream(String name):建立檔案輸出流以指定的名稱寫入檔案
            FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");
            /*
                做了三件事情:
                    A:調用系統功能建立了檔案
                    B:建立了位元組輸出流對象
                    C:讓位元組輸出流對象指向建立好的檔案
             */
    
            //void write(int b):将指定的位元組寫入此檔案輸出流
            fos.write(97);
    //        fos.write(57);
    //        fos.write(55);
    
            //最後都要釋放資源
            //void close():關閉此檔案輸出流并釋放與此流相關聯的任何系統資源。
            fos.close();
        }
    }
               

3.3位元組流寫資料的三種方式【應用】

  • 寫資料的方法分類
    方法名 說明
    void write(int b) 将指定的位元組寫入此檔案輸出流 一次寫一個位元組資料
    void write(byte[] b) 将 b.length位元組從指定的位元組數組寫入此檔案輸出流 一次寫一個位元組數組資料
    void write(byte[] b, int off, int len) 将 len位元組從指定的位元組數組開始,從偏移量off開始寫入此檔案輸出流 一次寫一個位元組數組的部分資料
  • 示例代碼
    public class FileOutputStreamDemo02 {
        public static void main(String[] args) throws IOException {
            //FileOutputStream(String name):建立檔案輸出流以指定的名稱寫入檔案
            FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");
            //new File(name)
    //        FileOutputStream fos = new FileOutputStream(new File("myByteStream\\fos.txt"));
    
            //FileOutputStream(File file):建立檔案輸出流以寫入由指定的 File對象表示的檔案
    //        File file = new File("myByteStream\\fos.txt");
    //        FileOutputStream fos2 = new FileOutputStream(file);
    //        FileOutputStream fos2 = new FileOutputStream(new File("myByteStream\\fos.txt"));
    
            //void write(int b):将指定的位元組寫入此檔案輸出流
    //        fos.write(97);
    //        fos.write(98);
    //        fos.write(99);
    //        fos.write(100);
    //        fos.write(101);
    
    //        void write(byte[] b):将 b.length位元組從指定的位元組數組寫入此檔案輸出流
    //        byte[] bys = {97, 98, 99, 100, 101};
            //byte[] getBytes():傳回字元串對應的位元組數組
            byte[] bys = "abcde".getBytes();
    //        fos.write(bys);
    
            //void write(byte[] b, int off, int len):将 len位元組從指定的位元組數組開始,從偏移量off開始寫入此檔案輸出流
    //        fos.write(bys,0,bys.length);
            fos.write(bys,1,3);
    
            //釋放資源
            fos.close();
        }
    }
               

3.4位元組流寫資料的兩個小問題【應用】

  • 位元組流寫資料如何實作換行
    • windows:\r\n
    • linux:\n
    • mac:\r
  • 位元組流寫資料如何實作追加寫入
    • public FileOutputStream(String name,boolean append)
    • 建立檔案輸出流以指定的名稱寫入檔案。如果第二個參數為true ,則位元組将寫入檔案的末尾而不是開頭
  • 示例代碼
    public class FileOutputStreamDemo03 {
        public static void main(String[] args) throws IOException {
            //建立位元組輸出流對象
    //        FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt");
            FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt",true);
    
            //寫資料
            for (int i = 0; i < 10; i++) {
                fos.write("hello".getBytes());
                fos.write("\r\n".getBytes());
            }
    
            //釋放資源
            fos.close();
        }
    }
               

3.5位元組流寫資料加異常處理【應用】

  • 異常處理格式
    • try-catch-finally
      try{
      	可能出現異常的代碼;
      }catch(異常類名 變量名){
      	異常的處理代碼;
      }finally{
      	執行所有清除操作;
      }
                 
    • finally特點
      • 被finally控制的語句一定會執行,除非JVM退出
  • 示例代碼
    public class FileOutputStreamDemo04 {
        public static void main(String[] args) {
            //加入finally來實作釋放資源
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream("myByteStream\\fos.txt");
                fos.write("hello".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
               

3.6位元組流讀資料(一次讀一個位元組資料)【應用】

  • 位元組輸入流
    • FileInputStream(String name):通過打開與實際檔案的連接配接來建立一個FileInputStream ,該檔案由檔案系統中的路徑名name命名
  • 位元組輸入流讀取資料的步驟
    • 建立位元組輸入流對象
    • 調用位元組輸入流對象的讀資料方法
    • 釋放資源
  • 示例代碼
    public class FileInputStreamDemo01 {
        public static void main(String[] args) throws IOException {
            //建立位元組輸入流對象
            //FileInputStream(String name)
            FileInputStream fis = new FileInputStream("myByteStream\\fos.txt");
    
            int by;
            /*
                fis.read():讀資料
                by=fis.read():把讀取到的資料指派給by
                by != -1:判斷讀取到的資料是否是-1
             */
            while ((by=fis.read())!=-1) {
                System.out.print((char)by);
            }
    
            //釋放資源
            fis.close();
        }
    }
               

3.7位元組流複制文本檔案【應用】

  • 案例需求

    把“E:\itcast\窗裡窗外.txt”複制到子產品目錄下的“窗裡窗外.txt”

  • 實作步驟
    • 複制文本檔案,其實就把文本檔案的内容從一個檔案中讀取出來(資料源),然後寫入到另一個檔案中(目的地)
    • 資料源:

      E:\itcast\窗裡窗外.txt — 讀資料 — InputStream — FileInputStream

    • 目的地:

      myByteStream\窗裡窗外.txt — 寫資料 — OutputStream — FileOutputStream

  • 代碼實作
    public class CopyTxtDemo {
        public static void main(String[] args) throws IOException {
            //根據資料源建立位元組輸入流對象
            FileInputStream fis = new FileInputStream("E:\\itcast\\窗裡窗外.txt");
            //根據目的地建立位元組輸出流對象
            FileOutputStream fos = new FileOutputStream("myByteStream\\窗裡窗外.txt");
    
            //讀寫資料,複制文本檔案(一次讀取一個位元組,一次寫入一個位元組)
            int by;
            while ((by=fis.read())!=-1) {
                fos.write(by);
            }
    
            //釋放資源
            fos.close();
            fis.close();
        }
    }
               

3.8位元組流讀資料(一次讀一個位元組數組資料)【應用】

  • 一次讀一個位元組數組的方法
    • public int read(byte[] b):從輸入流讀取最多b.length個位元組的資料
    • 傳回的是讀入緩沖區的總位元組數,也就是實際的讀取位元組個數
  • 示例代碼
    public class FileInputStreamDemo02 {
        public static void main(String[] args) throws IOException {
            //建立位元組輸入流對象
            FileInputStream fis = new FileInputStream("myByteStream\\fos.txt");
    
            /*
                hello\r\n
                world\r\n
    
                第一次:hello
                第二次:\r\nwor
                第三次:ld\r\nr
    
             */
    
            byte[] bys = new byte[1024]; //1024及其整數倍
            int len;
            while ((len=fis.read(bys))!=-1) {
                System.out.print(new String(bys,0,len));
            }
    
            //釋放資源
            fis.close();
        }
    }
               

3.9位元組流複制圖檔【應用】

  • 案例需求

    把“E:\itcast\mn.jpg”複制到子產品目錄下的“mn.jpg”

  • 實作步驟
    • 根據資料源建立位元組輸入流對象
    • 根據目的地建立位元組輸出流對象
    • 讀寫資料,複制圖檔(一次讀取一個位元組數組,一次寫入一個位元組數組)
    • 釋放資源
  • 代碼實作
    public class CopyJpgDemo {
        public static void main(String[] args) throws IOException {
            //根據資料源建立位元組輸入流對象
            FileInputStream fis = new FileInputStream("E:\\itcast\\mn.jpg");
            //根據目的地建立位元組輸出流對象
            FileOutputStream fos = new FileOutputStream("myByteStream\\mn.jpg");
    
            //讀寫資料,複制圖檔(一次讀取一個位元組數組,一次寫入一個位元組數組)
            byte[] bys = new byte[1024];
            int len;
            while ((len=fis.read(bys))!=-1) {
                fos.write(bys,0,len);
            }
    
            //釋放資源
            fos.close();
            fis.close();
        }
    }
               

4.位元組緩沖流

4.1位元組緩沖流構造方法【應用】

  • 位元組緩沖流介紹
    • lBufferOutputStream:該類實作緩沖輸出流。 通過設定這樣的輸出流,應用程式可以向底層輸出流寫入位元組,而不必為寫入的每個位元組導緻底層系統的調用
    • lBufferedInputStream:建立BufferedInputStream将建立一個内部緩沖區數組。 當從流中讀取或跳過位元組時,内部緩沖區将根據需要從所包含的輸入流中重新填充,一次很多位元組
  • 構造方法:
    方法名 說明
    BufferedOutputStream(OutputStream out) 建立位元組緩沖輸出流對象
    BufferedInputStream(InputStream in) 建立位元組緩沖輸入流對象
  • 示例代碼
    public class BufferStreamDemo {
        public static void main(String[] args) throws IOException {
            //位元組緩沖輸出流:BufferedOutputStream(OutputStream out)
     
            BufferedOutputStream bos = new BufferedOutputStream(new 				                                       FileOutputStream("myByteStream\\bos.txt"));
            //寫資料
            bos.write("hello\r\n".getBytes());
            bos.write("world\r\n".getBytes());
            //釋放資源
            bos.close();
        
    
            //位元組緩沖輸入流:BufferedInputStream(InputStream in)
            BufferedInputStream bis = new BufferedInputStream(new                                                          FileInputStream("myByteStream\\bos.txt"));
    
            //一次讀取一個位元組資料
    //        int by;
    //        while ((by=bis.read())!=-1) {
    //            System.out.print((char)by);
    //        }
    
            //一次讀取一個位元組數組資料
            byte[] bys = new byte[1024];
            int len;
            while ((len=bis.read(bys))!=-1) {
                System.out.print(new String(bys,0,len));
            }
    
            //釋放資源
            bis.close();
        }
    }
               

4.2位元組流複制視訊【應用】

  • 案例需求

    把“E:\itcast\位元組流複制圖檔.avi”複制到子產品目錄下的“位元組流複制圖檔.avi”

  • 實作步驟
    • 根據資料源建立位元組輸入流對象
    • 根據目的地建立位元組輸出流對象
    • 讀寫資料,複制視訊
    • 釋放資源
  • 代碼實作
    public class CopyAviDemo {
        public static void main(String[] args) throws IOException {
            //記錄開始時間
            long startTime = System.currentTimeMillis();
    
            //複制視訊
    //        method1();
    //        method2();
    //        method3();
            method4();
    
            //記錄結束時間
            long endTime = System.currentTimeMillis();
            System.out.println("共耗時:" + (endTime - startTime) + "毫秒");
        }
    
        //位元組緩沖流一次讀寫一個位元組數組
        public static void method4() throws IOException {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\itcast\\位元組流複制圖檔.avi"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\位元組流複制圖檔.avi"));
    
            byte[] bys = new byte[1024];
            int len;
            while ((len=bis.read(bys))!=-1) {
                bos.write(bys,0,len);
            }
    
            bos.close();
            bis.close();
        }
    
        //位元組緩沖流一次讀寫一個位元組
        public static void method3() throws IOException {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\itcast\\位元組流複制圖檔.avi"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\位元組流複制圖檔.avi"));
    
            int by;
            while ((by=bis.read())!=-1) {
                bos.write(by);
            }
    
            bos.close();
            bis.close();
        }
    
    
        //基本位元組流一次讀寫一個位元組數組
        public static void method2() throws IOException {
            //E:\\itcast\\位元組流複制圖檔.avi
            //子產品目錄下的 位元組流複制圖檔.avi
            FileInputStream fis = new FileInputStream("E:\\itcast\\位元組流複制圖檔.avi");
            FileOutputStream fos = new FileOutputStream("myByteStream\\位元組流複制圖檔.avi");
    
            byte[] bys = new byte[1024];
            int len;
            while ((len=fis.read(bys))!=-1) {
                fos.write(bys,0,len);
            }
    
            fos.close();
            fis.close();
        }
    
        //基本位元組流一次讀寫一個位元組
        public static void method1() throws IOException {
            //E:\\itcast\\位元組流複制圖檔.avi
            //子產品目錄下的 位元組流複制圖檔.avi
            FileInputStream fis = new FileInputStream("E:\\itcast\\位元組流複制圖檔.avi");
            FileOutputStream fos = new FileOutputStream("myByteStream\\位元組流複制圖檔.avi");
    
            int by;
            while ((by=fis.read())!=-1) {
                fos.write(by);
            }
    
            fos.close();
            fis.close();
        }
    }
               

5.字元流

5.1為什麼會出現字元流【了解】

  • 字元流的介紹

    由于位元組流操作中文不是特别的友善,是以Java就提供字元流

    字元流 = 位元組流 + 編碼表

  • 中文的位元組存儲方式

    用位元組流複制文本檔案時,文本檔案也會有中文,但是沒有問題,原因是最終底層操作會自動進行位元組拼接成中文,如何識别是中文的呢?

    漢字在存儲的時候,無論選擇哪種編碼存儲,第一個位元組都是負數

5.2編碼表【了解】

  • 什麼是字元集

    是一個系統支援的所有字元的集合,包括各國家文字、标點符号、圖形符号、數字等

    l計算機要準确的存儲和識别各種字元集符号,就需要進行字元編碼,一套字元集必然至少有一套字元編碼。常見字元集有ASCII字元集、GBXXX字元集、Unicode字元集等

  • 常見的字元集
    • ASCII字元集:

      lASCII:是基于拉丁字母的一套電腦編碼系統,用于顯示現代英語,主要包括控制字元(Enter鍵、倒退、換行鍵等)和可顯示字元(英文大小寫字元、阿拉伯數字和西文符号)

      基本的ASCII字元集,使用7位表示一個字元,共128字元。ASCII的擴充字元集使用8位表示一個字元,共256字元,友善支援歐洲常用字元。是一個系統支援的所有字元的集合,包括各國家文字、标點符号、圖形符号、數字等

    • GBXXX字元集:

      GBK:最常用的中文碼表。是在GB2312标準基礎上的擴充規範,使用了雙位元組編碼方案,共收錄了21003個漢字,完全相容GB2312标準,同時支援繁體漢字以及日韓漢字等

    • Unicode字元集:

      UTF-8編碼:可以用來表示Unicode标準中任意字元,它是電子郵件、網頁及其他存儲或傳送文字的應用 中,優先采用的編碼。網際網路工程工作小組(IETF)要求所有網際網路協定都必須支援UTF-8編碼。它使用一至四個位元組為每個字元編碼

      編碼規則:

      128個US-ASCII字元,隻需一個位元組編碼

      拉丁文等字元,需要二個位元組編碼

      大部分常用字(含中文),使用三個位元組編碼

      其他極少使用的Unicode輔助字元,使用四位元組編碼

5.3字元串中的編碼解碼問題【應用】

  • 相關方法
    方法名 說明
    byte[] getBytes() 使用平台的預設字元集将該 String編碼為一系列位元組
    byte[] getBytes(String charsetName) 使用指定的字元集将該 String編碼為一系列位元組
    String(byte[] bytes) 使用平台的預設字元集解碼指定的位元組數組來建立字元串
    String(byte[] bytes, String charsetName) 通過指定的字元集解碼指定的位元組數組來建立字元串
  • 代碼示範
    public class StringDemo {
        public static void main(String[] args) throws UnsupportedEncodingException {
            //定義一個字元串
            String s = "中國";
    
            //byte[] bys = s.getBytes(); //[-28, -72, -83, -27, -101, -67]
            //byte[] bys = s.getBytes("UTF-8"); //[-28, -72, -83, -27, -101, -67]
            byte[] bys = s.getBytes("GBK"); //[-42, -48, -71, -6]
            System.out.println(Arrays.toString(bys));
    
            //String ss = new String(bys);
            //String ss = new String(bys,"UTF-8");
            String ss = new String(bys,"GBK");
            System.out.println(ss);
        }
    }
               

5.4字元流中的編碼解碼問題【應用】

  • 字元流中和編碼解碼問題相關的兩個類
    • InputStreamReader:是從位元組流到字元流的橋梁

      它讀取位元組,并使用指定的編碼将其解碼為字元

      它使用的字元集可以由名稱指定,也可以被明确指定,或者可以接受平台的預設字元集
                 
    • OutputStreamWriter:是從字元流到位元組流的橋梁

      是從字元流到位元組流的橋梁,使用指定的編碼将寫入的字元編碼為位元組

      它使用的字元集可以由名稱指定,也可以被明确指定,或者可以接受平台的預設字元集
                 
  • 構造方法
    方法名 說明
    InputStreamReader(InputStream in) 使用預設字元編碼建立InputStreamReader對象
    InputStreamReader(InputStream in,String chatset) 使用指定的字元編碼建立InputStreamReader對象
    OutputStreamWriter(OutputStream out) 使用預設字元編碼建立OutputStreamWriter對象
    OutputStreamWriter(OutputStream out,String charset) 使用指定的字元編碼建立OutputStreamWriter對象
  • 代碼示範
    public class ConversionStreamDemo {
        public static void main(String[] args) throws IOException {
            //OutputStreamWriter osw = new OutputStreamWriter(new                                             FileOutputStream("myCharStream\\osw.txt"));
            OutputStreamWriter osw = new OutputStreamWriter(new                                              FileOutputStream("myCharStream\\osw.txt"),"GBK");
            osw.write("中國");
            osw.close();
    
            //InputStreamReader isr = new InputStreamReader(new 	                                         FileInputStream("myCharStream\\osw.txt"));
            InputStreamReader isr = new InputStreamReader(new                                                 FileInputStream("myCharStream\\osw.txt"),"GBK");
            //一次讀取一個字元資料
            int ch;
            while ((ch=isr.read())!=-1) {
                System.out.print((char)ch);
            }
            isr.close();
        }
    }
               

5.5字元流寫資料的5種方式【應用】

  • 方法介紹
    方法名 說明
    void write(int c) 寫一個字元
    void write(char[] cbuf) 寫入一個字元數組
    void write(char[] cbuf, int off, int len) 寫入字元數組的一部分
    void write(String str) 寫一個字元串
    void write(String str, int off, int len) 寫一個字元串的一部分
  • 重新整理和關閉的方法
    方法名 說明
    flush() 重新整理流,之後還可以繼續寫資料
    close() 關閉流,釋放資源,但是在關閉之前會先重新整理流。一旦關閉,就不能再寫資料
  • 代碼示範
    public class OutputStreamWriterDemo {
        public static void main(String[] args) throws IOException {
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"));
    
            //void write(int c):寫一個字元
    //        osw.write(97);
    //        osw.write(98);
    //        osw.write(99);
    
            //void writ(char[] cbuf):寫入一個字元數組
            char[] chs = {'a', 'b', 'c', 'd', 'e'};
    //        osw.write(chs);
    
            //void write(char[] cbuf, int off, int len):寫入字元數組的一部分
    //        osw.write(chs, 0, chs.length);
    //        osw.write(chs, 1, 3);
    
            //void write(String str):寫一個字元串
    //        osw.write("abcde");
    
            //void write(String str, int off, int len):寫一個字元串的一部分
    //        osw.write("abcde", 0, "abcde".length());
            osw.write("abcde", 1, 3);
    
            //釋放資源
            osw.close();
        }
    }
               

5.6字元流讀資料的2種方式【應用】

  • 方法介紹
    方法名 說明
    int read() 一次讀一個字元資料
    int read(char[] cbuf) 一次讀一個字元數組資料
  • 代碼示範
    public class InputStreamReaderDemo {
        public static void main(String[] args) throws IOException {
       
            InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
    
            //int read():一次讀一個字元資料
    //        int ch;
    //        while ((ch=isr.read())!=-1) {
    //            System.out.print((char)ch);
    //        }
    
            //int read(char[] cbuf):一次讀一個字元數組資料
            char[] chs = new char[1024];
            int len;
            while ((len = isr.read(chs)) != -1) {
                System.out.print(new String(chs, 0, len));
            }
    
            //釋放資源
            isr.close();
        }
    }
               

5.7字元流複制Java檔案【應用】

  • 案例需求

    把子產品目錄下的“ConversionStreamDemo.java” 複制到子產品目錄下的“Copy.java”

  • 實作步驟
    • 根據資料源建立字元輸入流對象
    • 根據目的地建立字元輸出流對象
    • 讀寫資料,複制檔案
    • 釋放資源
  • 代碼實作
    public class CopyJavaDemo01 {
        public static void main(String[] args) throws IOException {
            //根據資料源建立字元輸入流對象
            InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
            //根據目的地建立字元輸出流對象
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\Copy.java"));
    
            //讀寫資料,複制檔案
            //一次讀寫一個字元資料
    //        int ch;
    //        while ((ch=isr.read())!=-1) {
    //            osw.write(ch);
    //        }
    
            //一次讀寫一個字元數組資料
            char[] chs = new char[1024];
            int len;
            while ((len=isr.read(chs))!=-1) {
                osw.write(chs,0,len);
            }
    
            //釋放資源
            osw.close();
            isr.close();
        }
    }
               

5.8字元流複制Java檔案改進版【應用】

  • 案例需求

    使用便捷流對象,把子產品目錄下的“ConversionStreamDemo.java” 複制到子產品目錄下的“Copy.java”

  • 實作步驟
    • 根據資料源建立字元輸入流對象
    • 根據目的地建立字元輸出流對象
    • 讀寫資料,複制檔案
    • 釋放資源
  • 代碼實作
    public class CopyJavaDemo02 {
        public static void main(String[] args) throws IOException {
            //根據資料源建立字元輸入流對象
            FileReader fr = new FileReader("myCharStream\\ConversionStreamDemo.java");
            //根據目的地建立字元輸出流對象
            FileWriter fw = new FileWriter("myCharStream\\Copy.java");
    
            //讀寫資料,複制檔案
    //        int ch;
    //        while ((ch=fr.read())!=-1) {
    //            fw.write(ch);
    //        }
    
            char[] chs = new char[1024];
            int len;
            while ((len=fr.read(chs))!=-1) {
                fw.write(chs,0,len);
            }
    
            //釋放資源
            fw.close();
            fr.close();
        }
    }
               

5.9字元緩沖流【應用】

  • 字元緩沖流介紹
    • BufferedWriter:将文本寫入字元輸出流,緩沖字元,以提供單個字元,數組和字元串的高效寫入,可以指定緩沖區大小,或者可以接受預設大小。預設值足夠大,可用于大多數用途
    • BufferedReader:從字元輸入流讀取文本,緩沖字元,以提供字元,數組和行的高效讀取,可以指定緩沖區大小,或者可以使用預設大小。 預設值足夠大,可用于大多數用途
  • 構造方法
    方法名 說明
    BufferedWriter(Writer out) 建立字元緩沖輸出流對象
    BufferedReader(Reader in) 建立字元緩沖輸入流對象
  • 代碼示範
    public class BufferedStreamDemo01 {
        public static void main(String[] args) throws IOException {
            //BufferedWriter(Writer out)
            BufferedWriter bw = new BufferedWriter(new                                                            FileWriter("myCharStream\\bw.txt"));
            bw.write("hello\r\n");
            bw.write("world\r\n");
            bw.close();
    
            //BufferedReader(Reader in)
            BufferedReader br = new BufferedReader(new                                                           FileReader("myCharStream\\bw.txt"));
    
            //一次讀取一個字元資料
    //        int ch;
    //        while ((ch=br.read())!=-1) {
    //            System.out.print((char)ch);
    //        }
    
            //一次讀取一個字元數組資料
            char[] chs = new char[1024];
            int len;
            while ((len=br.read(chs))!=-1) {
                System.out.print(new String(chs,0,len));
            }
    
            br.close();
        }
    }
               

5.10字元緩沖流複制Java檔案【應用】

  • 案例需求

    把子產品目錄下的ConversionStreamDemo.java 複制到子產品目錄下的 Copy.java

  • 實作步驟
    • 根據資料源建立字元緩沖輸入流對象
    • 根據目的地建立字元緩沖輸出流對象
    • 讀寫資料,複制檔案,使用字元緩沖流特有功能實作
    • 釋放資源
  • 代碼實作
    public class CopyJavaDemo01 {
        public static void main(String[] args) throws IOException {
            //根據資料源建立字元緩沖輸入流對象
            BufferedReader br = new BufferedReader(new FileReader("myCharStream\\ConversionStreamDemo.java"));
            //根據目的地建立字元緩沖輸出流對象
            BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\Copy.java"));
    
            //讀寫資料,複制檔案
            //一次讀寫一個字元資料
    //        int ch;
    //        while ((ch=br.read())!=-1) {
    //            bw.write(ch);
    //        }
    
            //一次讀寫一個字元數組資料
            char[] chs = new char[1024];
            int len;
            while ((len=br.read(chs))!=-1) {
                bw.write(chs,0,len);
            }
    
            //釋放資源
            bw.close();
            br.close();
        }
    }
               

5.11字元緩沖流特有功能【應用】

  • 方法介紹

    BufferedWriter:

    方法名 說明
    void newLine() 寫一行行分隔符,行分隔符字元串由系統屬性定義
    BufferedReader:
    方法名 說明
    String readLine() 讀一行文字。 結果包含行的内容的字元串,不包括任何行終止字元如果流的結尾已經到達,則為null
  • 代碼示範
    public class BufferedStreamDemo02 {
        public static void main(String[] args) throws IOException {
    
            //建立字元緩沖輸出流
            BufferedWriter bw = new BufferedWriter(new                                                          FileWriter("myCharStream\\bw.txt"));
    
            //寫資料
            for (int i = 0; i < 10; i++) {
                bw.write("hello" + i);
                //bw.write("\r\n");
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            bw.close();
    
            //建立字元緩沖輸入流
            BufferedReader br = new BufferedReader(new                                                          FileReader("myCharStream\\bw.txt"));
    
            String line;
            while ((line=br.readLine())!=null) {
                System.out.println(line);
            }
    
            br.close();
        }
    }
               

5.12字元緩沖流特有功能複制Java檔案【應用】

  • 案例需求

    使用特有功能把子產品目錄下的ConversionStreamDemo.java 複制到子產品目錄下的 Copy.java

  • 實作步驟
    • 根據資料源建立字元緩沖輸入流對象
    • 根據目的地建立字元緩沖輸出流對象
    • 讀寫資料,複制檔案,使用字元緩沖流特有功能實作
    • 釋放資源
  • 代碼實作
    public class CopyJavaDemo02 {
        public static void main(String[] args) throws IOException {
            //根據資料源建立字元緩沖輸入流對象
            BufferedReader br = new BufferedReader(new FileReader("myCharStream\\ConversionStreamDemo.java"));
            //根據目的地建立字元緩沖輸出流對象
            BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\Copy.java"));
    
            //讀寫資料,複制檔案
            //使用字元緩沖流特有功能實作
            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            bw.close();
            br.close();
        }
    }
               

5.13IO流小結【了解】

  • 位元組流

    [外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-LwdB7T3d-1594954235893)(img\IO小結位元組流.jpg)]

  • 字元流

    [外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-FDvMDqLX-1594954235894)(img\IO小結字元流.jpg)]

6練習案例

6.1集合到檔案【應用】

  • 案例需求

    把文本檔案中的資料讀取到集合中,并周遊集合。要求:檔案中每一行資料是一個集合元素

  • 實作步驟
    • 建立字元緩沖輸入流對象
    • 建立ArrayList集合對象
    • 調用字元緩沖輸入流對象的方法讀資料
    • 把讀取到的字元串資料存儲到集合中
    • 釋放資源
    • 周遊集合
  • 代碼實作
    public class TxtToArrayListDemo {
        public static void main(String[] args) throws IOException {
            //建立字元緩沖輸入流對象
            BufferedReader br = new BufferedReader(new FileReader("myCharStream\\array.txt"));
    
            //建立ArrayList集合對象
            ArrayList<String> array = new ArrayList<String>();
    
            //調用字元緩沖輸入流對象的方法讀資料
            String line;
            while ((line=br.readLine())!=null) {
                //把讀取到的字元串資料存儲到集合中
                array.add(line);
            }
            //釋放資源
            br.close();
            //周遊集合
            for(String s : array) {
                System.out.println(s);
            }
        }
    }
               

6.2檔案到集合【應用】

  • 案例需求

    把ArrayList集合中的字元串資料寫入到文本檔案。要求:每一個字元串元素作為檔案中的一行資料

  • 實作步驟
    • 建立ArrayList集合
    • 往集合中存儲字元串元素
    • 建立字元緩沖輸出流對象
    • 周遊集合,得到每一個字元串資料
    • 調用字元緩沖輸出流對象的方法寫資料
    • 釋放資源
  • 代碼實作
    public class ArrayListToTxtDemo {
        public static void main(String[] args) throws IOException {
            //建立ArrayList集合
            ArrayList<String> array = new ArrayList<String>();
    
            //往集合中存儲字元串元素
            array.add("hello");
            array.add("world");
            array.add("java");
    
            //建立字元緩沖輸出流對象
            BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\array.txt"));
    
            //周遊集合,得到每一個字元串資料
            for(String s : array) {
                //調用字元緩沖輸出流對象的方法寫資料
                bw.write(s);
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            bw.close();
        }
    }
               

6.3點名器【應用】

  • 案例需求

    我有一個檔案裡面存儲了班級同學的姓名,每一個姓名占一行,要求通過程式實作随點名器

  • 實作步驟
    • 建立字元緩沖輸入流對象
    • 建立ArrayList集合對象
    • 調用字元緩沖輸入流對象的方法讀資料
    • 把讀取到的字元串資料存儲到集合中
    • 釋放資源
    • 使用Random産生一個随機數,随機數的範圍在:[0,集合的長度)
    • 把第6步産生的随機數作為索引到ArrayList集合中擷取值
    • 把第7步得到的資料輸出在控制台
  • 代碼實作
    public class CallNameDemo {
        public static void main(String[] args) throws IOException {
            //建立字元緩沖輸入流對象
            BufferedReader br = new BufferedReader(new FileReader("myCharStream\\names.txt"));
    
            //建立ArrayList集合對象
            ArrayList<String> array = new ArrayList<String>();
    
            //調用字元緩沖輸入流對象的方法讀資料
            String line;
            while ((line=br.readLine())!=null) {
                //把讀取到的字元串資料存儲到集合中
                array.add(line);
            }
    
            //釋放資源
            br.close();
    
            //使用Random産生一個随機數,随機數的範圍在:[0,集合的長度)
            Random r = new Random();
            int index = r.nextInt(array.size());
    
            //把第6步産生的随機數作為索引到ArrayList集合中擷取值
            String name = array.get(index);
    
            //把第7步得到的資料輸出在控制台
            System.out.println("幸運者是:" + name);
        }
    }
               

6.4集合到檔案改進版【應用】

  • 案例需求

    把ArrayList集合中的學生資料寫入到文本檔案。要求:每一個學生對象的資料作為檔案中的一行資料

    格式:學号,姓名,年齡,居住地 舉例:itheima001,林青霞,30,西安

  • 實作步驟
    • 定義學生類
    • 建立ArrayList集合
    • 建立學生對象
    • 把學生對象添加到集合中
    • 建立字元緩沖輸出流對象
    • 周遊集合,得到每一個學生對象
    • 把學生對象的資料拼接成指定格式的字元串
    • 調用字元緩沖輸出流對象的方法寫資料
    • 釋放資源
  • 代碼實作
    • 學生類
      public class Student {
          private String sid;
          private String name;
          private int age;
          private String address;
      
          public Student() {
          }
      
          public Student(String sid, String name, int age, String address) {
              this.sid = sid;
              this.name = name;
              this.age = age;
              this.address = address;
          }
      
          public String getSid() {
              return sid;
          }
      
          public void setSid(String sid) {
              this.sid = sid;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          public String getAddress() {
              return address;
          }
      
          public void setAddress(String address) {
              this.address = address;
          }
      }
                 
    • 測試類
      public class ArrayListToFileDemo {
          public static void main(String[] args) throws IOException {
              //建立ArrayList集合
              ArrayList<Student> array = new ArrayList<Student>();
      
              //建立學生對象
              Student s1 = new Student("itheima001", "林青霞", 30, "西安");
              Student s2 = new Student("itheima002", "張曼玉", 35, "武漢");
              Student s3 = new Student("itheima003", "王祖賢", 33, "鄭州");
      
              //把學生對象添加到集合中
              array.add(s1);
              array.add(s2);
              array.add(s3);
      
              //建立字元緩沖輸出流對象
              BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\students.txt"));
      
              //周遊集合,得到每一個學生對象
              for (Student s : array) {
                  //把學生對象的資料拼接成指定格式的字元串
                  StringBuilder sb = new StringBuilder();
                  sb.append(s.getSid()).append(",").append(s.getName()).append(",").append(s.getAge()).append(",").append(s.getAddress());
      
                  //調用字元緩沖輸出流對象的方法寫資料
                  bw.write(sb.toString());
                  bw.newLine();
                  bw.flush();
              }
      
              //釋放資源
              bw.close();
          }
      }
                 

6.5檔案到集合改進版【應用】

  • 案例需求

    把文本檔案中的資料讀取到集合中,并周遊集合。要求:檔案中每一行資料是一個學生對象的成員變量值

    舉例:itheima001,林青霞,30,西安

  • 實作步驟
    • 定義學生類
    • 建立字元緩沖輸入流對象
    • 建立ArrayList集合對象
    • 調用字元緩沖輸入流對象的方法讀資料
    • 把讀取到的字元串資料用split()進行分割,得到一個字元串數組
    • 建立學生對象
    • 把字元串數組中的每一個元素取出來對應的指派給學生對象的成員變量值
    • 把學生對象添加到集合
    • 釋放資源
    • 周遊集合
  • 代碼實作
    • 學生類

      同上

    • 測試類
      public class FileToArrayListDemo {
          public static void main(String[] args) throws IOException {
              //建立字元緩沖輸入流對象
              BufferedReader br = new BufferedReader(new FileReader("myCharStream\\students.txt"));
      
              //建立ArrayList集合對象
              ArrayList<Student> array = new ArrayList<Student>();
      
              //調用字元緩沖輸入流對象的方法讀資料
              String line;
              while ((line = br.readLine()) != null) {
                  //把讀取到的字元串資料用split()進行分割,得到一個字元串數組
                  String[] strArray = line.split(",");
      
                  //建立學生對象
                  Student s = new Student();
                  //把字元串數組中的每一個元素取出來對應的指派給學生對象的成員變量值
                  //itheima001,林青霞,30,西安
                  s.setSid(strArray[0]);
                  s.setName(strArray[1]);
                  s.setAge(Integer.parseInt(strArray[2]));
                  s.setAddress(strArray[3]);
      
                  //把學生對象添加到集合
                  array.add(s);
              }
      
              //釋放資源
              br.close();
      
              //周遊集合
              for (Student s : array) {
                  System.out.println(s.getSid() + "," + s.getName() + "," + s.getAge() + "," + s.getAddress());
              }
          }
      }
                 

7.IO流案例

7.1集合到檔案資料排序改進版【應用】

7.1.1案例需求

  • 鍵盤錄入5個學生資訊(姓名,國文成績,數學成績,英語成績)。要求按照成績總分從高到低寫入文本檔案
  • 格式:姓名,國文成績,數學成績,英語成績 舉例:林青霞,98,99,100

7.1.2分析步驟

  1. 定義學生類
  2. 建立TreeSet集合,通過比較器排序進行排序
  3. 鍵盤錄入學生資料
  4. 建立學生對象,把鍵盤錄入的資料對應指派給學生對象的成員變量
  5. 把學生對象添加到TreeSet集合
  6. 建立字元緩沖輸出流對象
  7. 周遊集合,得到每一個學生對象
  8. 把學生對象的資料拼接成指定格式的字元串
  9. 調用字元緩沖輸出流對象的方法寫資料
  10. 釋放資源

1.1.3代碼實作

  • 學生類
    public class Student {
        // 姓名
        private String name;
        // 國文成績
        private int chinese;
        // 數學成績
        private int math;
        // 英語成績
        private int english;
    
        public Student() {
            super();
        }
    
        public Student(String name, int chinese, int math, int english) {
            super();
            this.name = name;
            this.chinese = chinese;
            this.math = math;
            this.english = english;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getChinese() {
            return chinese;
        }
    
        public void setChinese(int chinese) {
            this.chinese = chinese;
        }
    
        public int getMath() {
            return math;
        }
    
        public void setMath(int math) {
            this.math = math;
        }
    
        public int getEnglish() {
            return english;
        }
    
        public void setEnglish(int english) {
            this.english = english;
        }
    
        public int getSum() {
            return this.chinese + this.math + this.english;
        }
    }
               
  • 測試類
    public class TreeSetToFileDemo {
        public static void main(String[] args) throws IOException {
            //建立TreeSet集合,通過比較器排序進行排序
            TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
                @Override
                public int compare(Student s1, Student s2) {
                    //成績總分從高到低
                    int num = s2.getSum() - s1.getSum();
                    //次要條件
                    int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
                    int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
                    int num4 = num3 == 0 ? s1.getName().compareTo(s2.getName()) : num3;
                    return num4;
                }
            });
    
            //鍵盤錄入學生資料
            for (int i = 0; i < 5; i++) {
                Scanner sc = new Scanner(System.in);
                System.out.println("請錄入第" + (i + 1) + "個學生資訊:");
                System.out.println("姓名:");
                String name = sc.nextLine();
                System.out.println("國文成績:");
                int chinese = sc.nextInt();
                System.out.println("數學成績:");
                int math = sc.nextInt();
                System.out.println("英語成績:");
                int english = sc.nextInt();
    
                //建立學生對象,把鍵盤錄入的資料對應指派給學生對象的成員變量
                Student s = new Student();
                s.setName(name);
                s.setChinese(chinese);
                s.setMath(math);
                s.setEnglish(english);
    
                //把學生對象添加到TreeSet集合
                ts.add(s);
            }
    
            //建立字元緩沖輸出流對象
            BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\ts.txt"));
    
            //周遊集合,得到每一個學生對象
            for (Student s : ts) {
                //把學生對象的資料拼接成指定格式的字元串
                //格式:姓名,國文成績,數學成績,英語成績
                StringBuilder sb = new StringBuilder();
                sb.append(s.getName()).append(",").append(s.getChinese()).append(",").append(s.getMath()).append(",").append(s.getEnglish()).append(",").append(s.getSum());
    
    //            調用字元緩沖輸出流對象的方法寫資料
                bw.write(sb.toString());
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            bw.close();
        }
    }
               

7.2複制單級檔案夾【應用】

7.2.1案例需求

  • 把“E:\itcast”這個檔案夾複制到子產品目錄下

7.2.2分析步驟

  1. 建立資料源目錄File對象,路徑是E:\itcast
  2. 擷取資料源目錄File對象的名稱
  3. 建立目的地目錄File對象,路徑由(子產品名+第2步擷取的名稱)組成
  4. 判斷第3步建立的File是否存在,如果不存在,就建立
  5. 擷取資料源目錄下所有檔案的File數組
  6. 周遊File數組,得到每一個File對象,該File對象,其實就是資料源檔案
  7. 擷取資料源檔案File對象的名稱
  8. 建立目的地檔案File對象,路徑由(目的地目錄+第7步擷取的名稱)組成
  9. 複制檔案

    由于不清楚資料源目錄下的檔案都是什麼類型的,是以采用位元組流複制檔案

    采用參數為File的構造方法
               

7.2.3代碼實作

public class CopyFolderDemo {
    public static void main(String[] args) throws IOException {
        //建立資料源目錄File對象,路徑是E:\\itcast
        File srcFolder = new File("E:\\itcast");

        //擷取資料源目錄File對象的名稱(itcast)
        String srcFolderName = srcFolder.getName();

        //建立目的地目錄File對象,路徑名是子產品名+itcast組成(myCharStream\\itcast)
        File destFolder = new File("myCharStream",srcFolderName);

        //判斷目的地目錄對應的File是否存在,如果不存在,就建立
        if(!destFolder.exists()) {
            destFolder.mkdir();
        }

        //擷取資料源目錄下所有檔案的File數組
        File[] listFiles = srcFolder.listFiles();

        //周遊File數組,得到每一個File對象,該File對象,其實就是資料源檔案
        for(File srcFile : listFiles) {
            //資料源檔案:E:\\itcast\\mn.jpg
            //擷取資料源檔案File對象的名稱(mn.jpg)
            String srcFileName = srcFile.getName();
            //建立目的地檔案File對象,路徑名是目的地目錄+mn.jpg組成(myCharStream\\itcast\\mn.jpg)
            File destFile = new File(destFolder,srcFileName);
            //複制檔案
            copyFile(srcFile,destFile);
        }
    }

    private static void copyFile(File srcFile, File destFile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));

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

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

7.3複制多級檔案夾【應用】

7.3.1案例需求

  • 把“E:\itcast”這個檔案夾複制到 F盤目錄下

7.3.2分析步驟

  1. 建立資料源File對象,路徑是E:\itcast
  2. 建立目的地File對象,路徑是F:\
  3. 寫方法實作檔案夾的複制,參數為資料源File對象和目的地File對象
  4. 判斷資料源File是否是檔案

    是檔案:直接複制,用位元組流

    不是檔案:
    
     	 在目的地下建立該目錄
    
     	周遊擷取該目錄下的所有檔案的File數組,得到每一個File對象
    
     	回到3繼續(遞歸)
               

7.3.3代碼實作

public class CopyFoldersDemo {
    public static void main(String[] args) throws IOException {
        //建立資料源File對象,路徑是E:\\itcast
        File srcFile = new File("E:\\itcast");
        //建立目的地File對象,路徑是F:\\
        File destFile = new File("F:\\");

        //寫方法實作檔案夾的複制,參數為資料源File對象和目的地File對象
        copyFolder(srcFile,destFile);
    }

    //複制檔案夾
    private static void copyFolder(File srcFile, File destFile) throws IOException {
        //判斷資料源File是否是目錄
        if(srcFile.isDirectory()) {
            //在目的地下建立和資料源File名稱一樣的目錄
            String srcFileName = srcFile.getName();
            File newFolder = new File(destFile,srcFileName); //F:\\itcast
            if(!newFolder.exists()) {
                newFolder.mkdir();
            }

            //擷取資料源File下所有檔案或者目錄的File數組
            File[] fileArray = srcFile.listFiles();

            //周遊該File數組,得到每一個File對象
            for(File file : fileArray) {
                //把該File作為資料源File對象,遞歸調用複制檔案夾的方法
                copyFolder(file,newFolder);
            }
        } else {
            //說明是檔案,直接複制,用位元組流
            File newFile = new File(destFile,srcFile.getName());
            copyFile(srcFile,newFile);
        }
    }

    //位元組緩沖流複制檔案
    private static void copyFile(File srcFile, File destFile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));

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

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

7.4複制檔案的異常處理【應用】

7.4.1基本做法

public class CopyFileDemo {
    public static void main(String[] args) {

    }

    //try...catch...finally
    private static void method2() {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            fr = new FileReader("fr.txt");
            fw = new FileWriter("fw.txt");

            char[] chs = new char[1024];
            int len;
            while ((len = fr.read()) != -1) {
                fw.write(chs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fw!=null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fr!=null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //抛出處理
    private static void method1() throws IOException {
        FileReader fr = new FileReader("fr.txt");
        FileWriter fw = new FileWriter("fw.txt");

        char[] chs = new char[1024];
        int len;
        while ((len = fr.read()) != -1) {
            fw.write(chs, 0, len);
        }

        fw.close();
        fr.close();
    }
}
           

7.4.2JDK7版本改進

public class CopyFileDemo {
    public static void main(String[] args) {

    }

    //JDK7的改進方案
    private static void method3() {
        try(FileReader fr = new FileReader("fr.txt");
            FileWriter fw = new FileWriter("fw.txt");){
            char[] chs = new char[1024];
            int len;
            while ((len = fr.read()) != -1) {
                fw.write(chs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
           

7.4.3JDK9版本改進

public class CopyFileDemo {
    public static void main(String[] args) {

    }

    //JDK9的改進方案
    private static void method4() throws IOException {
        FileReader fr = new FileReader("fr.txt");
        FileWriter fw = new FileWriter("fw.txt");
        try(fr;fw){
            char[] chs = new char[1024];
            int len;
            while ((len = fr.read()) != -1) {
                fw.write(chs, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
           

8.IO特殊操作流

8.1标準輸入流【應用】

  • System類中有兩個靜态的成員變量
    • public static final InputStream in:标準輸入流。通常該流對應于鍵盤輸入或由主機環境或使用者指定的另一個輸入源
    • public static final PrintStream out:标準輸出流。通常該流對應于顯示輸出或由主機環境或使用者指定的另一個輸出目标
  • 自己實作鍵盤錄入資料
    public class SystemInDemo {
        public static void main(String[] args) throws IOException {
            //public static final InputStream in:标準輸入流
    //        InputStream is = System.in;
    
    //        int by;
    //        while ((by=is.read())!=-1) {
    //            System.out.print((char)by);
    //        }
    
            //如何把位元組流轉換為字元流?用轉換流
    //        InputStreamReader isr = new InputStreamReader(is);
    //        //使用字元流能不能夠實作一次讀取一行資料呢?可以
    //        //但是,一次讀取一行資料的方法是字元緩沖輸入流的特有方法
    //        BufferedReader br = new BufferedReader(isr);
    
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
            System.out.println("請輸入一個字元串:");
            String line = br.readLine();
            System.out.println("你輸入的字元串是:" + line);
    
            System.out.println("請輸入一個整數:");
            int i = Integer.parseInt(br.readLine());
            System.out.println("你輸入的整數是:" + i);
    
            //自己實作鍵盤錄入資料太麻煩了,是以Java就提供了一個類供我們使用
            Scanner sc = new Scanner(System.in);
        }
    }
               

8.2标準輸出流【應用】

  • System類中有兩個靜态的成員變量
    • public static final InputStream in:标準輸入流。通常該流對應于鍵盤輸入或由主機環境或使用者指定的另一個輸入源
    • public static final PrintStream out:标準輸出流。通常該流對應于顯示輸出或由主機環境或使用者指定的另一個輸出目标
  • 輸出語句的本質:是一個标準的輸出流
    • PrintStream ps = System.out;
    • PrintStream類有的方法,System.out都可以使用
  • 示例代碼
    public class SystemOutDemo {
        public static void main(String[] args) {
            //public static final PrintStream out:标準輸出流
            PrintStream ps = System.out;
    
            //能夠友善地列印各種資料值
    //        ps.print("hello");
    //        ps.print(100);
    
    //        ps.println("hello");
    //        ps.println(100);
    
            //System.out的本質是一個位元組輸出流
            System.out.println("hello");
            System.out.println(100);
    
            System.out.println();
    //        System.out.print();
        }
    }
               

8.3位元組列印流【應用】

  • 列印流分類
    • 位元組列印流:PrintStream
    • 字元列印流:PrintWriter
  • 列印流的特點
    • 隻負責輸出資料,不負責讀取資料
    • 永遠不會抛出IOException
    • 有自己的特有方法
  • 位元組列印流
    • PrintStream(String fileName):使用指定的檔案名建立新的列印流
    • 使用繼承父類的方法寫資料,檢視的時候會轉碼;使用自己的特有方法寫資料,檢視的資料原樣輸出
    • 可以改變輸出語句的目的地

      public static void setOut(PrintStream out):重新配置設定“标準”輸出流

  • 示例代碼
    public class PrintStreamDemo {
        public static void main(String[] args) throws IOException {
            //PrintStream(String fileName):使用指定的檔案名建立新的列印流
            PrintStream ps = new PrintStream("myOtherStream\\ps.txt");
    
            //寫資料
            //位元組輸出流有的方法
    //        ps.write(97);
    
            //使用特有方法寫資料
    //        ps.print(97);
    //        ps.println();
    //        ps.print(98);
            ps.println(97);
            ps.println(98);
            
            //釋放資源
            ps.close();
        }
    }
               

8.4字元列印流【應用】

  • 字元列印流構造房方法
    方法名 說明
    PrintWriter(String fileName) 使用指定的檔案名建立一個新的PrintWriter,而不需要自動執行重新整理
    PrintWriter(Writer out, boolean autoFlush) 建立一個新的PrintWriter out:字元輸出流 autoFlush: 一個布爾值,如果為真,則println , printf ,或format方法将重新整理輸出緩沖區
  • 示例代碼
    public class PrintWriterDemo {
        public static void main(String[] args) throws IOException {
            //PrintWriter(String fileName) :使用指定的檔案名建立一個新的PrintWriter,而不需要自動執行行重新整理
    //        PrintWriter pw = new PrintWriter("myOtherStream\\pw.txt");
    
    //        pw.write("hello");
    //        pw.write("\r\n");
    //        pw.flush();
    //        pw.write("world");
    //        pw.write("\r\n");
    //        pw.flush();
    
    //        pw.println("hello");
            /*
                pw.write("hello");
                pw.write("\r\n");
             */
    //        pw.flush();
    //        pw.println("world");
    //        pw.flush();
    
            //PrintWriter(Writer out, boolean autoFlush):建立一個新的PrintWriter
            PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\pw.txt"),true);
    //        PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\pw.txt"),false);
    
            pw.println("hello");
            /*
                pw.write("hello");
                pw.write("\r\n");
                pw.flush();
             */
            pw.println("world");
    
            pw.close();
        }
    }
               

8.5複制Java檔案列印流改進版【應用】

  • 案例需求
    • 把子產品目錄下的PrintStreamDemo.java 複制到子產品目錄下的 Copy.java
  • 分析步驟
    • 根據資料源建立字元輸入流對象
    • 根據目的地建立字元輸出流對象
    • 讀寫資料,複制檔案
    • 釋放資源
  • 代碼實作
    public class CopyJavaDemo {
        public static void main(String[] args) throws IOException {
            /*
            //根據資料源建立字元輸入流對象
            BufferedReader br = new BufferedReader(new FileReader("myOtherStream\\PrintStreamDemo.java"));
            //根據目的地建立字元輸出流對象
            BufferedWriter bw = new BufferedWriter(new FileWriter("myOtherStream\\Copy.java"));
    
            //讀寫資料,複制檔案
            String line;
            while ((line=br.readLine())!=null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            //釋放資源
            bw.close();
            br.close();
            */
    
            //根據資料源建立字元輸入流對象
            BufferedReader br = new BufferedReader(new FileReader("myOtherStream\\PrintStreamDemo.java"));
            //根據目的地建立字元輸出流對象
            PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\Copy.java"),true);
    
            //讀寫資料,複制檔案
            String line;
            while ((line=br.readLine())!=null) {
                pw.println(line);
            }
    
            //釋放資源
            pw.close();
            br.close();
        }
    }
               

8.6對象序列化流【應用】

  • 對象序列化介紹
    • 對象序列化:就是将對象儲存到磁盤中,或者在網絡中傳輸對象
    • 這種機制就是使用一個位元組序清單示一個對象,該位元組序列包含:對象的類型、對象的資料和對象中存儲的屬性等資訊
    • 位元組序列寫到檔案之後,相當于檔案中持久儲存了一個對象的資訊
    • 反之,該位元組序列還可以從檔案中讀取回來,重構對象,對它進行反序列化
  • 對象序列化流: ObjectOutputStream
    • 将Java對象的原始資料類型和圖形寫入OutputStream。 可以使用ObjectInputStream讀取(重構)對象。 可以通過使用流的檔案來實作對象的持久存儲。 如果流是網絡套接字流,則可以在另一個主機上或另一個程序中重構對象
  • 構造方法
    方法名 說明
    ObjectOutputStream(OutputStream out) 建立一個寫入指定的OutputStream的ObjectOutputStream
  • 序列化對象的方法
    方法名 說明
    void writeObject(Object obj) 将指定的對象寫入ObjectOutputStream
  • 示例代碼
    • 學生類
      public class Student implements Serializable {
          private String name;
          private int age;
      
          public Student() {
          }
      
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Student{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      }
                 
    • 測試類
      public class ObjectOutputStreamDemo {
          public static void main(String[] args) throws IOException {
              //ObjectOutputStream(OutputStream out):建立一個寫入指定的OutputStream的ObjectOutputStream
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));
      
              //建立對象
              Student s = new Student("林青霞",30);
      
              //void writeObject(Object obj):将指定的對象寫入ObjectOutputStream
              oos.writeObject(s);
      
              //釋放資源
              oos.close();
          }
      }
                 
  • 注意事項
    • 一個對象要想被序列化,該對象所屬的類必須必須實作Serializable 接口
    • Serializable是一個标記接口,實作該接口,不需要重寫任何方法

8.7對象反序列化流【應用】

  • 對象反序列化流: ObjectInputStream
    • ObjectInputStream反序列化先前使用ObjectOutputStream編寫的原始資料和對象
  • 構造方法
    方法名 說明
    ObjectInputStream(InputStream in) 建立從指定的InputStream讀取的ObjectInputStream
  • 反序列化對象的方法
    方法名 說明
    Object readObject() 從ObjectInputStream讀取一個對象
  • 示例代碼
    public class ObjectInputStreamDemo {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            //ObjectInputStream(InputStream in):建立從指定的InputStream讀取的ObjectInputStream
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));
    
            //Object readObject():從ObjectInputStream讀取一個對象
            Object obj = ois.readObject();
    
            Student s = (Student) obj;
            System.out.println(s.getName() + "," + s.getAge());
    
            ois.close();
        }
    }
               

8.8serialVersionUID&transient【應用】

  • serialVersionUID
    • 用對象序列化流序列化了一個對象後,假如我們修改了對象所屬的類檔案,讀取資料會不會出問題呢?
      • 會出問題,會抛出InvalidClassException異常
    • 如果出問題了,如何解決呢?
      • 重新序列化
      • 給對象所屬的類加一個serialVersionUID
        • private static final long serialVersionUID = 42L;
  • transient
    • 如果一個對象中的某個成員變量的值不想被序列化,又該如何實作呢?
      • 給該成員變量加transient關鍵字修飾,該關鍵字标記的成員變量不參與序列化過程
  • 示例代碼
    • 學生類
      public class Student implements Serializable {
          private static final long serialVersionUID = 42L;
          private String name;
      //    private int age;
          private transient int age;
      
          public Student() {
          }
      
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
      //    @Override
      //    public String toString() {
      //        return "Student{" +
      //                "name='" + name + '\'' +
      //                ", age=" + age +
      //                '}';
      //    }
      }
                 
    • 測試類
      public class ObjectStreamDemo {
          public static void main(String[] args) throws IOException, ClassNotFoundException {
      //        write();
              read();
          }
      
          //反序列化
          private static void read() throws IOException, ClassNotFoundException {
              ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));
              Object obj = ois.readObject();
              Student s = (Student) obj;
              System.out.println(s.getName() + "," + s.getAge());
              ois.close();
          }
      
          //序列化
          private static void write() throws IOException {
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));
              Student s = new Student("林青霞", 30);
              oos.writeObject(s);
              oos.close();
          }
      }
                 

9.Properties集合

9.1Properties作為Map集合的使用【應用】

  • Properties介紹
    • 是一個Map體系的集合類
    • Properties可以儲存到流中或從流中加載
    • 屬性清單中的每個鍵及其對應的值都是一個字元串
  • Properties基本使用
    public class PropertiesDemo01 {
        public static void main(String[] args) {
            //建立集合對象
    //        Properties<String,String> prop = new Properties<String,String>(); //錯誤
            Properties prop = new Properties();
    
            //存儲元素
            prop.put("itheima001", "林青霞");
            prop.put("itheima002", "張曼玉");
            prop.put("itheima003", "王祖賢");
    
            //周遊集合
            Set<Object> keySet = prop.keySet();
            for (Object key : keySet) {
                Object value = prop.get(key);
                System.out.println(key + "," + value);
            }
        }
    }
               

9.2Properties作為Map集合的特有方法【應用】

  • 特有方法
    方法名 說明
    Object setProperty(String key, String value) 設定集合的鍵和值,都是String類型,底層調用 Hashtable方法 put
    String getProperty(String key) 使用此屬性清單中指定的鍵搜尋屬性
    Set stringPropertyNames() 從該屬性清單中傳回一個不可修改的鍵集,其中鍵及其對應的值是字元串
  • 示例代碼
    public class PropertiesDemo02 {
        public static void main(String[] args) {
            //建立集合對象
            Properties prop = new Properties();
    
            //Object setProperty(String key, String value):設定集合的鍵和值,都是String類型,底層調用Hashtable方法put
            prop.setProperty("itheima001", "林青霞");
            /*
                Object setProperty(String key, String value) {
                    return put(key, value);
                }
    
                Object put(Object key, Object value) {
                    return map.put(key, value);
                }
             */
            prop.setProperty("itheima002", "張曼玉");
            prop.setProperty("itheima003", "王祖賢");
    
            //String getProperty(String key):使用此屬性清單中指定的鍵搜尋屬性
    //        System.out.println(prop.getProperty("itheima001"));
    //        System.out.println(prop.getProperty("itheima0011"));
    
    //        System.out.println(prop);
    
            //Set<String> stringPropertyNames():從該屬性清單中傳回一個不可修改的鍵集,其中鍵及其對應的值是字元串
            Set<String> names = prop.stringPropertyNames();
            for (String key : names) {
    //            System.out.println(key);
                String value = prop.getProperty(key);
                System.out.println(key + "," + value);
            }
        }
    }
               

9.3Properties和IO流相結合的方法【應用】

  • 和IO流結合的方法
    方法名 說明
    void load(InputStream inStream) 從輸入位元組流讀取屬性清單(鍵和元素對)
    void load(Reader reader) 從輸入字元流讀取屬性清單(鍵和元素對)
    void store(OutputStream out, String comments) 将此屬性清單(鍵和元素對)寫入此 Properties表中,以适合于使用 load(InputStream)方法的格式寫入輸出位元組流
    void store(Writer writer, String comments) 将此屬性清單(鍵和元素對)寫入此 Properties表中,以适合使用 load(Reader)方法的格式寫入輸出字元流
  • 示例代碼
    public class PropertiesDemo03 {
        public static void main(String[] args) throws IOException {
            //把集合中的資料儲存到檔案
    //        myStore();
    
            //把檔案中的資料加載到集合
            myLoad();
    
        }
    
        private static void myLoad() throws IOException {
            Properties prop = new Properties();
    
            //void load(Reader reader):
            FileReader fr = new FileReader("myOtherStream\\fw.txt");
            prop.load(fr);
            fr.close();
    
            System.out.println(prop);
        }
    
        private static void myStore() throws IOException {
            Properties prop = new Properties();
    
            prop.setProperty("itheima001","林青霞");
            prop.setProperty("itheima002","張曼玉");
            prop.setProperty("itheima003","王祖賢");
    
            //void store(Writer writer, String comments):
            FileWriter fw = new FileWriter("myOtherStream\\fw.txt");
            prop.store(fw,null);
            fw.close();
        }
    }
               

9.4遊戲次數案例【應用】

  • 案例需求
    • 實作猜數字小遊戲隻能試玩3次,如果還想玩,提示:遊戲試玩已結束,想玩請充值(www.itcast.cn)
  • 分析步驟
    1. 寫一個遊戲類,裡面有一個猜數字的小遊戲
    2. 寫一個測試類,測試類中有main()方法,main()方法中寫如下代碼:

      從檔案中讀取資料到Properties集合,用load()方法實作

      檔案已經存在:game.txt
      
         裡面有一個資料值:count=0
      
      	通過Properties集合擷取到玩遊戲的次數
      
      	判斷次數是否到到3次了
      
         如果到了,給出提示:遊戲試玩已結束,想玩請充值(www.itcast.cn)
      
         如果不到3次:
      
         	次數+1,重新寫回檔案,用Properties的store()方法實作玩遊戲
                 
  • 代碼實作
    public class PropertiesTest {
        public static void main(String[] args) throws IOException {
            //從檔案中讀取資料到Properties集合,用load()方法實作
            Properties prop = new Properties();
    
            FileReader fr = new FileReader("myOtherStream\\game.txt");
            prop.load(fr);
            fr.close();
    
            //通過Properties集合擷取到玩遊戲的次數
            String count = prop.getProperty("count");
            int number = Integer.parseInt(count);
    
            //判斷次數是否到到3次了
            if(number >= 3) {
                //如果到了,給出提示:遊戲試玩已結束,想玩請充值(www.itcast.cn)
                System.out.println("遊戲試玩已結束,想玩請充值(www.itcast.cn)");
            } else {
                //玩遊戲
                GuessNumber.start();
    
                //次數+1,重新寫回檔案,用Properties的store()方法實作
                number++;
                prop.setProperty("count",String.valueOf(number));
                FileWriter fw = new FileWriter("myOtherStream\\game.txt");
                prop.store(fw,null);
                fw.close();
            }
        }
    }