1. 程式人生 > >21 IO(字元流)&字元流其他內容&遞迴

21 IO(字元流)&字元流其他內容&遞迴

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,read()的返回值是int
      	System.out.println((char)ch);						//將讀到的字元強轉後列印
      }
      
      fr.close();												//關流 
    

21.02_IO流(字元流FileWriter)

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

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

21.03_IO流(字元流的拷貝)

public static void demo1() throws FileNotFoundException, IOException {
		FileReader fr = new FileReader("xxx.txt");
		FileWriter fw = new FileWriter("zzz.txt");
		
		int c;
		while((c = fr.read()) != -1) {
			fw.write(c);
		}
		
		fr.close();
		fw.close();				//Writer類中有一個2k的小緩衝區,如果不關流,就會將內容寫到緩衝區裡,關流會將緩衝區內容重新整理,再關閉
	}

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"
  •   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流(將文字反轉)

  • 將一個文字文件上的文字反轉,第一行和倒數第一行交換,第二行和倒數第二行交換
public static void main(String[] args) throws IOException {
		//流物件儘量晚開早關
		// 1,建立輸入輸出流物件
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		
		//2,建立集合物件
		ArrayList<String> list = new ArrayList<>();
		//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);									//設定行號,行號從101開始
      while((line = lnr.readLine()) != null) {
      	System.out.println(lnr.getLineNumber() + ":" + line);//獲取行號
      }
      
      lnr.close(); 
    

21.11_IO流(裝飾設計模式)

	/**
	 * @param args
	 * 裝飾設計模式的好處是:
	 * 耦合性不強,被裝飾的類的變化與裝飾類的變化無關
	 */
	public static void main(String[] args) {
		HeiMaStudent hms = new HeiMaStudent(new Student());
		hms.code();
	}



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 {
	//1,獲取被裝飾類的引用
	private Student s;						//獲取學生引用
	
	//2,在構造方法中傳入被裝飾類的物件
	public HeiMaStudent(Student s) {
		this.s = s;
	}

	//3,對原有的功能進行升級
	@Override
	public void code() {
		s.code();
		System.out.println("ssh");
		System.out.println("資料庫");
		System.out.println("大資料");
		System.out.println("...");
	}
}

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

  • FileReader是使用預設碼錶讀取檔案, 如果需要使用指定碼錶讀取, 那麼可以使用InputStreamReader(位元組流,編碼表)
  • FileWriter是使用預設碼錶寫出檔案, 如果需要使用指定碼錶寫出, 那麼可以使用OutputStreamWriter(位元組流,編碼表)
public static void demo2() throws UnsupportedEncodingException,
			FileNotFoundException, IOException {
		InputStreamReader isr = new InputStreamReader(new FileInputStream("utf-8.txt"), "uTf-8");	//指定碼錶讀字元
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"), "gbk");	//指定碼錶寫字元
		
		int c;
		while((c = isr.read()) != -1) {
			osw.write(c);
		}
		
		isr.close();
		osw.close();
	}
public static void main(String[] args) throws IOException {   //使用緩衝字元輸入流
		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 c;
		while((c = br.read()) != -1) {
			bw.write(c);
		}
		
		br.close();
		bw.close();
	}

21.13_IO流(轉換流圖解)

  • 畫圖分析轉換流
    在這裡插入圖片描述

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

  • 獲取一個文字上每個字元出現的次數,將結果寫在times.txt上
/**
	 * 獲取一個文字上每個字元出現的次數,將結果寫在times.txt上
	 * 
	 * 1,建立帶緩衝區的輸入流物件
	 * 2,建立雙列集合物件,目的是把字元當作鍵,把字元出現的次數當作值
	 * 3,通過讀取不斷向集合中儲存,儲存的時候要判斷,如果不包含這個鍵就將鍵和值為1儲存,如果包含就將鍵和值加1儲存
	 * 4,關閉輸入流
	 * 5,建立輸出流物件
	 * 6,將結果寫出
	 * 7,關閉輸出流
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//1,建立帶緩衝區的輸入流物件
		BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
		//2,建立雙列集合物件,目的是把字元當作鍵,把字元出現的次數當作值
		HashMap<Character, Integer> hm = new HashMap<>();
		//3,通過讀取不斷向集合中儲存,儲存的時候要判斷,如果不包含這個鍵就將鍵和值為1儲存,如果包含就將鍵和值加1儲存
		int c;
		while((c = br.read()) != -1) {
			char ch = (char)c;
			/*if(!hm.containsKey(ch)) {
				hm.put(ch, 1);
			}else {
				hm.put(ch, hm.get(ch) +  1);
			}*/
			
			hm.put(ch, !hm.containsKey(ch)? 1 : hm.get(ch) + 1);
		}
		//4,關閉輸入流
		br.close();
		//5,建立輸出流物件
		BufferedWriter bw = new BufferedWriter(new FileWriter("times.txt"));
		//6,將結果寫出
		
		for (Character key : hm.keySet()) {
			bw.write(key + "=" + hm.get(key));
		}
		
		bw.close();
	}

21.15_IO流(試用版軟體)

  • 當我們下載一個試用版軟體,沒有購買正版的時候,每執行一次就會提醒我們還有多少次使用機會用學過的IO流知識,模擬試用版軟體,試用10次機會,執行一次就提示一次您還有幾次機會,如果次數到了提示請購買正版
public static void main(String[] args) throws IOException {
		//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的階乘
/**
	 * 遞迴:方法自己呼叫自己
	 * 5!
	 * 5 * 4 * 3 * 2 * 1
	 * 
	 * 5 * fun(4)(代表4!)
	 * 		4 * fun(3)(代表3!)
	 * 				3 * fun(2)(代表2!) 
	 * 						2 * fun(1)(代表1!)
	 * 遞迴的弊端:不能呼叫次數過多,容易導致棧記憶體溢位
	 * 遞迴的好處:不用知道迴圈次數
	 * 
	 * 構造方法是否可以遞迴呼叫?
	 * 構造方法不能使用遞迴呼叫
	 * 
	 * 遞迴呼叫是否必須有返回值?
	 * 不一定(可以有,也可以沒有)
	 */
	public static void main(String[] args) {
		/*int result = 1;
		
		for(int i = 1; i <= 5; i++) {
			result = result * i;
		}
		
		System.out.println(result);*/
		System.out.println(fun(6000));
	}
	
	public static int fun(int num) {
		if(num == 1) {
			return 1;
		}else {
			return num * fun(num - 1);
		}
	}

21.17_File類(練習)

  • 需求:從鍵盤輸入接收一個資料夾路徑,打印出該資料夾下所有的.java檔名
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);
			}
		}
	}