1. 程式人生 > >IO流(字元流)+JAVA學習筆記-DAY21

IO流(字元流)+JAVA學習筆記-DAY21

21.01_IO流(字元流FileReader)

  • 1.字元流是什麼
    • 字元流是可以直接讀寫字元的IO流
    • 字元流讀取字元, 就要先讀取到位元組資料, 然後轉為字元. 如果要寫出字元, 需要把字元轉為位元組再寫出.
  • 2.FileReader
    • FileReader類的read()方法可以按照字元大小讀取
  • FileReader fr = new FileReader("aaa.txt");              //建立輸入流物件,關聯aaa.txt
    int ch;
    while((ch = fr.read()) != -1) {                         //將讀到的字元賦值給ch
        System.out.println((char)ch);                       //將讀到的字元強轉後列印
    }
    
    fr.close();                                             //關流 
    

21.02_IO流(字元流FileWriter)

  • FileWriter類的write()方法可以自動把字元轉為位元組寫出

    FileWriter fw = new FileWriter("aaa.txt");
    fw.write("aaa");
    fw.write(97);
    fw.close();
    

21.03_IO流(字元流的拷貝)

FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");

int ch;
while((ch = fr.read()) != -1) {
    fw.write(ch);
}

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

21.04_IO流(什麼情況下使用字元流)

  • 字元流也可以拷貝文字檔案, 但不推薦使用. 因為讀取時會把位元組轉為字元, 寫出時還要把字元轉回位元組.
  • 程式需要讀取一段文字, 或者需要寫出一段文字的時候可以使用字元流
  • 讀取的時候是按照字元的大小讀取的,不會出現半個中文
  • 寫出的時候可以直接將字串寫出,不用轉換為位元組陣列

21.05_IO流(字元流是否可以拷貝非純文字的檔案)

  • 不可以拷貝非純文字的檔案
  • 因為在讀的時候會將位元組轉換為字元,在轉換過程中,可能找不到對應的字元,就會用?代替,寫出的時候會將字元轉換成位元組寫出去
  • 如果是?,直接寫出,這樣寫出之後的檔案就亂了,看不了了

21.06_IO流(自定義字元陣列的拷貝)

  • FileReader fr = new FileReader("aaa.txt");          //建立字元輸入流,關聯aaa.txt
    FileWriter fw = new FileWriter("bbb.txt");          //建立字元輸出流,關聯bbb.txt
    
    int len;
    char[] arr = new char[1024*8];                      //建立字元陣列
    while((len = fr.read(arr)) != -1) {                 //將資料讀到字元陣列中
        fw.write(arr, 0, len);                          //從字元陣列將資料寫到檔案上
    }
    
    fr.close();                                         //關流釋放資源
    fw.close(); 
    

21.07_IO流(帶緩衝的字元流)

  • BufferedReader的read()方法讀取字元時會一次讀取若干字元到緩衝區, 然後逐個返回給程式, 降低讀取檔案的次數, 提高效率
  • BufferedWriter的write()方法寫出字元時會先寫到緩衝區, 緩衝區寫滿時才會寫到檔案, 降低寫檔案的次數, 提高效率
  • BufferedReader br = new BufferedReader(new FileReader("aaa.txt"));  //建立字元輸入流物件,關聯aaa.txt
    BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt"));  //建立字元輸出流物件,關聯bbb.txt
    
    int ch;             
    while((ch = br.read()) != -1) {     //read一次,會先將緩衝區讀滿,從緩衝去中一個一個的返給臨時變數ch
        bw.write(ch);                   //write一次,是將資料裝到字元陣列,裝滿後再一起寫出去
    }
    
    br.close();                         //關流
    bw.close();  
    

21.08_IO流(readLine()和newLine()方法)

  • BufferedReader的readLine()方法可以讀取一行字元(不包含換行符號)
  • BufferedWriter的newLine()可以輸出一個跨平臺的換行符號”\r\n”
    • newLine()與\r\n的區別
    • newLine()是跨平臺的方法
    • \r\n只支援的是windows系統

      BufferedReader br = new BufferedReader(new FileReader("aaa.txt"));
      BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt"));
      String line;
      while((line = br.readLine()) != null) {
          bw.write(line);
          //bw.write("\r\n");                 //只支援windows系統
          bw.newLine();                       //跨平臺的
      }
      
      br.close();
      bw.close(); 
      

21.09_IO流(將文字反轉)

  • 將一個文字文件上的文字反轉,第一行和倒數第一行交換,第二行和倒數第二行交換

    //改寫後是儘量晚開早關
    // 1,建立輸入輸出流物件
    BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
    
    //2,建立集合物件
    ArrayList<String> list = new ArrayList<String>();
    //3,將讀到的資料儲存在集合中
    String line;
    while((line = br.readLine()) != null) {
        list.add(line);
    }
    br.close();                                         //關流
    
    //4,倒著遍歷集合將資料寫到檔案上
    BufferedWriter bw = new BufferedWriter(new FileWriter("revzzz.txt"));
    for(int i = list.size() - 1; i >= 0; i--) {
        bw.write(list.get(i));
        bw.newLine();
    }
    //5,關流
    
    bw.close();
    

21.10_IO流(LineNumberReader)

  • LineNumberReader是BufferedReader的子類, 具有相同的功能, 並且可以統計行號
    • 呼叫getLineNumber()方法可以獲取當前行號
    • 呼叫setLineNumber()方法可以設定當前行號

  • LineNumberReader lnr = new LineNumberReader(new FileReader(“aaa.txt”));
    String line;
    lnr.setLineNumber(100); //設定行號
    while((line = lnr.readLine()) != null) {
    System.out.println(lnr.getLineNumber() + “:” + line);//獲取行號
    }
    從101開始
    lnr.close();

21.11_IO流(裝飾設計模式)

  • 對原有功能進行提升
  • 裝飾設計模式的好處是:

    • 耦合性不強,被裝飾的類的變化與裝飾類的變化無關

      interface Coder {
          public void code();
      }
      
      class Student implements Coder {
      
          @Override
          public void code() {
              System.out.println("javase");
              System.out.println("javaweb");
          }
      
      }
      
      class HeiMaStudent implements Coder {
          private Student s;                      //獲取到被包裝的類的引用
          public ItcastStudent(Student s) {       //通過建構函式建立物件的時候,傳入被包裝的物件
              this.s = s;
          }
          @Override
          public void code() {                    //對其原有功能進行升級
              s.code();
              System.out.println("資料庫");
              System.out.println("ssh");
              System.out.println("安卓");
              System.out.println(".....");
          }
      
      } 
      

21.12_IO流(使用指定的碼錶讀寫字元)

  • FileReader是使用預設碼錶讀取檔案, 如果需要使用指定碼錶讀取, 那麼可以使用InputStreamReader(位元組流,編碼表)
  • FileWriter是使用預設碼錶寫出檔案, 如果需要使用指定碼錶寫出, 那麼可以使用OutputStreamWriter(位元組流,編碼表)
  • BufferedReader br =                                     //高效的用指定的編碼表讀
            new BufferedReader(new InputStreamReader(new FileInputStream("UTF-8.txt"), "UTF-8"));
    BufferedWriter bw =                                     //高效的用指定的編碼表寫
            new BufferedWriter(new OutputStreamWriter(new FileOutputStream("GBK.txt"), "GBK"));
    int ch;
    while((ch = br.read()) != -1) {
        bw.write(ch);
    }
    
    br.close();
    bw.close();
    

21.13_IO流(轉換流圖解)

  • 畫圖分析轉換流

21.14_IO流(獲取文字上字元出現的次數)

  • 獲取一個文字上每個字元出現的次數,將結果寫在times.txt上

    /**
         * 獲取一個文字上每個字元出現的次數,將結果寫在times.txt上
         * 
         * 分析:
         * 1,建立帶緩衝的輸入流物件
         * 2,建立雙列集合物件TreeMap
         * 3,將讀到的字元儲存在雙列集合中,儲存的時候要做判斷,如果不包含這個鍵,就將鍵和1儲存,如果包含這個鍵,就將該鍵和值加1儲存
         * 4,關閉輸入流
         * 5,建立輸出流物件
         * 6,遍歷集合將集合中的內容寫到times.txt中
         * 7,關閉輸出流
         * @throws IOException 
         */
        public static void main(String[] args) throws IOException {
            //1,建立帶緩衝的輸入流物件
            BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
            //2,建立雙列集合物件TreeMap
            TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
            //3,將讀到的字元儲存在雙列集合中,儲存的時候要做判斷,如果不包含這個鍵,就將鍵和1儲存,如果包含這個鍵,就將該鍵和值加1儲存
            int ch;
            while((ch = br.read()) != -1) {
                char c = (char)ch;                  //強制型別轉換
                /*if(!tm.containsKey(c)) {
                    tm.put(c, 1);
                }else {
                    tm.put(c, tm.get(c) + 1);
                }*/
                tm.put(c, !tm.containsKey(c) ? 1 : tm.get(c) + 1);
            }
            //4,關閉輸入流
            br.close();
            //5,建立輸出流物件
            BufferedWriter bw = new BufferedWriter(new FileWriter("times.txt"));
            //6,遍歷集合將集合中的內容寫到times.txt中
            for(Character key : tm.keySet()) {
                switch (key) {
                case '\t':
                    bw.write("\\t" + "=" + tm.get(key));    
                    break;
                case '\n':
                    bw.write("\\n" + "=" + tm.get(key)); 
                    break;
                case '\r':
                    bw.write("\\r" + "=" + tm.get(key)); 
                    break;
                default:
                    bw.write(key + "=" + tm.get(key));          //寫出鍵和值
                    break;
                }
                bw.newLine();
            }
            //7,關閉輸出流
            bw.close();
        }
    

21.15_IO流(試用版軟體)

  • 當我們下載一個試用版軟體,沒有購買正版的時候,每執行一次就會提醒我們還有多少次使用機會。用學過的IO流知識,模擬試用版軟體,試用10次機會,執行一次就提示一次您還有幾次機會,如果次數到了提示請購買正版

    //1,建立帶緩衝的輸入流物件,因為要使用readLine方法,可以保證資料的原樣性
    BufferedReader br = new BufferedReader(new FileReader("config.txt"));
    //2,將讀到的字串轉換為int數
    String line = br.readLine();
    int times = Integer.parseInt(line);                 //將數字字串轉換為數字
    //3,對int數進行判斷,如果大於0,就將其--寫回去,如果不大於0,就提示請購買正版
    if(times > 0) {
        //4,在if判斷中要將--的結果列印,並將結果通過輸出流寫到檔案上
        System.out.println("您還有" + times-- + "次機會");
        FileWriter fw = new FileWriter("config.txt");
        fw.write(times + "");
        fw.close();
    }else {
        System.out.println("您的試用次數已到,請購買正版");
    }
    //關閉流
    br.close();
    

21.16_File類(遞迴)

  • 遞迴的弊端:不能呼叫次數過多,容易導致棧記憶體溢位

    • 遞迴的好處:不用知道迴圈次數

    • 構造方法是否可以遞迴呼叫?

      • 構造方法不能使用遞迴呼叫
    • 遞迴呼叫是否必須有返回值?

      • 不一定(可以有,也可以沒有)
  • 5的階乘

    public static  int Count(int num) {
        if (num == 1) {
            return num;
        } else {
            return num*Count(num-1);
        }
    
    }
    

21.17_File類(練習)

  • 需求:從鍵盤輸入接收一個資料夾路徑,打印出該資料夾下所有的.java檔名

    /**
     * 需求:從鍵盤輸入接收一個資料夾路徑,打印出該資料夾下所有的.java檔名
     * 
     * 分析:
     * 從鍵盤接收一個資料夾路徑
     * 1,如果錄入的是不存在,給與提示
     * 2,如果錄入的是檔案路徑,給與提示
     * 3,如果是資料夾路徑,直接返回
     * 
     * 打印出該資料夾下所有的.java檔名
     * 1,獲取到該資料夾路徑下的所有的檔案和資料夾,儲存在File陣列中
     * 2,遍歷陣列,對每一個檔案或資料夾做判斷
     * 3,如果是檔案,並且字尾是.java的,就列印
     * 4,如果是資料夾,就遞迴呼叫
     */
    public static void main(String[] args) {
        File dir = getDir();
        printJavaFile(dir);
    }
    
    /*
     * 獲取鍵盤錄入的資料夾路徑
     * 1,返回值型別File
     * 2,不需要有引數
     */
    public static File getDir() {
        Scanner sc = new Scanner(System.in);                //建立鍵盤錄入物件
        System.out.println("請輸入一個資料夾路徑");
        while(true) {
            String line = sc.nextLine();                    //將鍵盤錄入的資料夾路徑儲存
            File dir = new File(line);                      //封裝成File物件
            if(!dir.exists()) {
                System.out.println("您錄入的資料夾路徑不存在,請重新錄入");
            }else if(dir.isFile()) {
                System.out.println("您錄入的是檔案路徑,請重新錄入資料夾路徑");
            }else {
                return dir;
            }
        }
    }
    /*
     * 獲取資料夾路徑下的所.java檔案
     * 1,返回值型別 void
     * 2,引數列表File dir
     */
    public static void printJavaFile(File dir) {
        //1,獲取到該資料夾路徑下的所有的檔案和資料夾,儲存在File陣列中
        File[] subFiles = dir.listFiles();
        //2,遍歷陣列,對每一個檔案或資料夾做判斷
        for (File subFile : subFiles) {
            //3,如果是檔案,並且字尾是.java的,就列印
            if(subFile.isFile() && subFile.getName().endsWith(".java")) {
                System.out.println(subFile);
            //4,如果是資料夾,就遞迴呼叫
            }else if (subFile.isDirectory()){
                printJavaFile(subFile);
            }
        }
    }
    

21.18_IO流(總結)

  • 1.會用BufferedReader讀取GBK碼錶和UTF-8碼錶的字元
  • 2.會用BufferedWriter寫出字元到GBK碼錶和UTF-8碼錶的檔案中
  • 3.會使用BufferedReader從鍵盤讀取一行