黑馬程序員-io 學習筆記

------- android培訓java培訓、期待與您交流! ----------

關於文件流: 

首先是四大基本抽象流:字節流:InputStream、OutputStream,字符流:Reader、Writer;輸入流:InputStream、Reader,輸出流:
OutputStream、Writer;後面的所有流都是這四個的子類;

文件流:FileInputStream、FileOutputStream,FileReader、FileWriter,文件流算是四大基本抽象流的最初級實現類,前面兩個是字節
流,可以用於任何格式文件的讀寫(因爲文件的最基本存儲形式就是字節數據),後面兩個是字符流,只能用來處理文本文件;
字節輸入流簡單實例

        
import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
public class InputStreamDemo01{
 public static void main(String args[]) throws Exception{ // 異常拋出,不處理
  // 第1步、使用File類找到一個文件
  File f= new File("d:" + File.separator + "test.txt") ; // 聲明File對象
  // 第2步、通過子類實例化父類對象
  InputStream input = null ; // 準備好一個輸入的對象
  input = new FileInputStream(f)  ; // 通過對象多態性,進行實例化
  // 第3步、進行讀操作
  byte b[] = new byte[1024] ;  // 所有的內容都讀到此數組之中
  input.read(b) ;  // 讀取內容
  // 第4步、關閉輸出流
  input.close() ;      // 關閉輸出流
  System.out.println("內容爲:" + new String(b)) ; // 把byte數組變爲字符串輸出
 }
};

  

字節輸出流簡單實例

 import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo01{
 public static void main(String args[]) throws Exception{ // 異常拋出,不處理
  // 第1步、使用File類找到一個文件
  File f= new File("d:" + File.separator + "test.txt") ; // 聲明File對象
  // 第2步、通過子類實例化父類對象
  OutputStream out = null ; // 準備好一個輸出的對象
  out = new FileOutputStream(f)  ; // 通過對象多態性,進行實例化
  // 第3步、進行寫操作
  String str = "Hello World!!!" ;  // 準備一個字符串
  byte b[] = str.getBytes() ;   // 只能輸出byte數組,所以將字符串變爲byte數組
  out.write(b) ;      // 將內容輸出,保存文件
  // 第4步、關閉輸出流
  out.close() ;      // 關閉輸出流
 }
};


字符輸入流簡單實例

 

 import java.io.File ;
 import java.io.Reader ;
 import java.io.FileReader ;
 public class ReaderDemo01{
 public static void main(String args[]) throws Exception{ // 異常拋出,不處理
  // 第1步、使用File類找到一個文件
  File f= new File("d:" + File.separator + "test.txt") ; // 聲明File對象
  // 第2步、通過子類實例化父類對象
  Reader input = null ; // 準備好一個輸入的對象
  input = new FileReader(f)  ; // 通過對象多態性,進行實例化
  // 第3步、進行讀操作
  char c[] = new char[1024] ;  // 所有的內容都讀到此數組之中
  int len = input.read(c) ;  // 讀取內容
  // 第4步、關閉輸出流
  input.close() ;      // 關閉輸出流
  System.out.println("內容爲:" + new String(c,0,len)) ; // 把字符數組變爲字符串輸出
 }
};


 

字符輸出流簡單實例

 

import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo01{
 public static void main(String args[]) throws Exception{ // 異常拋出,不處理
  // 第1步、使用File類找到一個文件
  File f= new File("d:" + File.separator + "test.txt") ; // 聲明File對象
  // 第2步、通過子類實例化父類對象
  Writer out = null ; // 準備好一個輸出的對象
  out = new FileWriter(f)  ; // 通過對象多態性,進行實例化
  // 第3步、進行寫操作
  String str = "Hello World!!!" ;  // 準備一個字符串
  out.write(str) ;      // 將內容輸出,保存文件
  // 第4步、關閉輸出流
  out.close() ;      // 關閉輸出流
 }
}


練習Copy一個文件夾下的.java到指定目錄下,並改後綴名.jad

  1,首先得到一個文件夾下的所有文件

              File[] fs = file.listFiles(FilenameFilter f);此處可以用內部類實現,並重寫accept方法。

     2,根據accept返回的boolen值,判斷是不是一個文件和是不是以指定的後綴名命名的。

     3,定義一個copy方法,判斷目標文件夾是不是存在,不存在則創建,如果存在並且是一個文件夾

     4,定義輸入流和輸出流,while判斷是否讀取到數據 如果讀到數據則寫入流中

     5,關閉輸入流和輸出流
   

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;

public class Test9 {
	public static void main(String[] args) throws Exception {
		File file = new File("d:\\java");// 得到一個file對象
		// 判斷源目錄是不是目錄,是不是存在
		if (!(file.exists() && file.isDirectory())) {
			throw new Exception("源目錄不存在");// 不存在則拋出異常
		}
		File[] fs = file.listFiles(new FilenameFilter() {// 匿名內部類類
					@Override
					public boolean accept(File dir, String name) {// 重寫FilenameFilter的accept方法,接受文件的類型
						// TODO Auto-generated method stub
						File file = new File(dir, name);
						if (file.isFile() && name.endsWith(".java")) {// 判斷文件後綴名是不是java和是不是文件
							return true;
						} else {
							return false;
						}
					}
				});
		// 循環遍歷這個符合條件的數組,調用複製的方法。
		for (int i = 0; i < fs.length; i++) {
			copy(fs[i]);// 複製文件
		}
	}

	private static void copy(File file) throws Exception {
		File f2 = new File("d:\\jad");
		OutputStream ouput = null;
		InputStream input = null;
		if (f2.isDirectory() && f2.exists()) {
			try {
				String path = f2.getPath() + "\\"
						+ file.getName().replaceAll("\\.java$", ".jad");// 改變後綴名
				input = new FileInputStream(file);// 定義輸入流
				ouput = new FileOutputStream(path);// 定義輸出流
				int temp = 0;
				while ((temp = input.read()) != -1) {// 讀取流
					ouput.write(temp);// 寫入流
				}
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				// 關閉輸入流和輸出流
				input.close();
				ouput.close();
			}
		} else {
			f2.mkdir();// 目標不存在則創建一個文件夾
		}
	}
}


 練習 複製一個文件夾到另一個目錄中去

      

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

//周可
public class Test9 {
	public static void main(String[] args) throws IOException {
		String src = "c:\\a";// 源文件夾
		String des = "d:\\a";// 目的文件夾
		File filesrc = new File(src);// 源文件夾
		new File(des).mkdir();// 創建目標文件夾
		if (filesrc.isDirectory() && filesrc.exists()) {// 判斷源是不是一個文件夾,是不是存在
			File[] files = filesrc.listFiles();// 得到所有的文件盒文件夾
			for (int i = 0; i < files.length; i++) {// 循環遍歷,分別對文件文件夾處理
				if (files[i].isFile()) {
					// 如果是文件調用複製文件的方法。
					copyFile(files[i],
							new File(des + "\\" + files[i].getName()));

				}
				// 如果是文件夾,調用複製文件的方法。
				if (files[i].isDirectory()) {
					// 得到絕對路徑的方法
					copyDirectiory(files[i].getAbsolutePath(), des + "\\"
							+ files[i].getName());
				}
			}
		} else {
			System.out.println("源文件不存在");
		}
	}

	/**
	 * 
	 * @param srcFile
	 *            源文件
	 * @param desFilePath
	 *            //目標文件
	 * @throws IOException
	 */
	public static void copyFile(File srcFile, File desFilePath)
			throws IOException {

		InputStream input = new FileInputStream(srcFile);// 得到文件的輸入流
		BufferedInputStream bis = new BufferedInputStream(input);// 利用緩衝區技術封裝輸入流流對象
		OutputStream out = new FileOutputStream(desFilePath);// 得到文件的輸出流
		BufferedOutputStream bos = new BufferedOutputStream(out);// 利用緩衝區技術封裝輸出流對象
		int ch = 0;// 讀取的字節
		byte[] by = new byte[1024];// 緩衝數組
		while ((ch = bis.read(by)) != -1) {// 如果讀取到了數據
			bos.write(by, 0, ch);// 寫入緩衝區中。
		}
		// bos.flush();可以不用緩衝,緩衝區到緩衝區
		bos.close();// 關閉緩衝輸入流
		bis.close();// 關閉緩衝輸出流
	}

	/**
	 * 複製一個文件夾
	 * 
	 * @param src
	 *            源文件夾路徑
	 * @param des
	 *            目標文件夾路徑
	 * @throws IOException
	 */
	public static void copyDirectiory(String src, String des)
			throws IOException {// 目標,源 文件夾的路徑
		File fdes = new File(des);// 創建目標file對象
		fdes.mkdir();// 創建目標文件夾
		File fsrc = new File(src);// 創建源file對象
		File[] files = fsrc.listFiles();// 源文件夾的所有文件
		for (int i = 0; i < files.length; i++) {
			if (files[i].isFile()) {// 如果是文件
				// 調用複製文件的方法
				File desFile = new File(des + "\\" + files[i].getName());
				copyFile(files[i], desFile);// 調用
			} else if (files[i].isDirectory()) {// 如果是文件夾,複製文件夾
				copyDirectiory(files[i].getAbsolutePath(), des + "\\"
						+ files[i].getName());
			}
		}
	}
}


 

 緩衝區技術

        緩衝區的出現提高了對數據的讀寫效率。

對應的兩個類

     BufferedWriter Writer子類

     BufferedReader  Reader子類

緩衝區要結合流纔可以使用。

在流的基礎上對流的功能進行了增強。

緩衝區的出現是爲了提高流的操作效率而出現的。

所以創建緩衝區之前必須要先有流對象。

 寫入字符流緩衝區

 

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;


public class BufferDemo {
    public static void main(String[] args) throws IOException {
     //創建一個字符寫入流對象
  FileWriter fw=new FileWriter("buf.txt");
  //爲了提高字符謝如柳效率,加入了緩衝技術
  //只要將需要被提高效率的流對象作爲參數傳遞給緩衝區的構造函數即可
  BufferedWriter bufw=new BufferedWriter(fw);
  for(int x=1;x<5;x++){
   bufw.write("abcd"+x);
   bufw.newLine();//該緩衝區中提供了一個跨平臺的換行符。
   bufw.flush();
  }
 /// bufw.write("abced");
  //只要用到緩衝區,就要記得刷新
  bufw.flush();
  //其實關閉緩衝區,就是關閉緩衝區的流對象
  bufw.close();
  
 }
}


字符讀取流緩衝區

    從字符輸入流中讀取文本,緩衝各個字符,從而實現字符,數組,和行的搞笑讀取

    在進行對象建立的時候,也要有一個被緩衝的對象。

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;


public class BufferDemo2 {
   public static void main(String[] args) throws IOException {
    //創建一個讀取流對象和文件相關聯
  FileReader fr=new FileReader("buf.txt");
  //爲了提高效率。加入緩衝區將字符讀取流對象作爲參數傳遞給緩衝對象的構造函數
  BufferedReader bufr=new BufferedReader(fr);
  String line=null;
  while((line=bufr.readLine())!=null){//一行一行的讀取最爲方便
   System.out.println(line);
  }
  String s1=bufr.readLine();//讀取一行只返回回車符之前的數據內容,不帶任何行終止符
  System.out.println("s1"+s1);
  bufr.close();
}
}

通過緩衝區複製一個文本文件

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 通過緩衝區複製一個java文件
 * 
 * @author Administrator
 * 
 */
public class Test9 {
	public static void main(String[] args) {
		BufferedReader bufr = null;
		BufferedWriter bufw = null;
		try {
			bufr = new BufferedReader(new FileReader("c:\\Test8.java"));//緩衝讀取流
			bufw = new BufferedWriter(new FileWriter("d:\\Test8.java"));//緩衝輸出流
			String line = null;
           
			while ((line = bufr.readLine()) != null) {
				bufw.write(line);//把獨到的這一行寫出去

				bufw.newLine();// 這裏一定要寫入一個新行,因爲readLine不代表換行,關於readLine方法,見下面的講解

			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				bufr.close();// 關閉讀取流
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				bufw.close();//關閉寫入流
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}



 

readLine方法原理:

無論是讀一行,獲取多個字符。其實最終都是在在硬盤上一個一個的讀取。所以最終使用的還是read方法一次讀一個的方法。讀到回車符好\r\n時,就返回該數據中的數據。其實就是臨時存入一個緩衝數組中。 比read方法高效很多。

返回:包含該行內容的字符串,不包含任何行終止符,如果已到達流末尾,則返回null。

明白了BufferedReader類中特有方法readLine的原理後,

可以自定義一個類中包含功能和readLine一致的方法。來模擬一下BuffreedReader

package com.jbit.zhkk;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Test3 {
	public static void main(String[] args) throws Exception {
		MyBufferedReader mybuf = null;

		FileReader fr = new FileReader("a.txt");
		mybuf = new MyBufferedReader(fr);
		String line = null;

		while ((line = mybuf.myReadLine()) != null) {
			System.out.println(line);
		}
		mybuf.myClose();

	}
}

class MyBufferedReader {
	private FileReader r;

	public MyBufferedReader(FileReader r) {
		this.r = r;
	}

	// 可以一次讀取一行數據的方法。
	public String myReadLine() throws IOException {// 誰調用誰處理,不需要try
		// 定義一個臨時容器,原BufferedReader封裝的是字符數組。
		// 爲了演示方便,定義一個StringBuilder容器,因爲最終還是要將數據變成字符串
		StringBuilder sb = new StringBuilder();
		int ch = 0;

		while ((ch = r.read()) != -1) {
			// 回車符有兩個一個\r,一個\n
			if (ch == '\r') {
				continue;// 繼續讀取,不存儲
			}
			if (ch == '\n') {// 到了行結尾,變成字符串返回
				return sb.toString();
			} else {// 如果不是\r或\n的話添加
				sb.append((char) ch);
			}
                        }
			//
			if (sb.length() != 0) {// 如果不加這個判斷,代碼是有問題的,假如鼠標的光標在末行的最後,最後一行不打印了。
				// 相反加入這個判斷,可以將緩衝區有數據,卻沒有被返回。直接返回null了。,直接將緩衝區的數據返回
				return sb.toString();
			}
				return null;// 讀到結尾沒有數據返回null
	}

	/**
	 * 怎麼關呢? 緩衝區爲了提高FielReader而存在的
	 */
	public void myClose() {
		try {
			r.close();// 流關閉
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 

裝飾模式:

   其實ReadLine的出現增強read方法的功能,那麼增強功能的方式,將被增強的對象傳遞給增強類,以上的代碼其實就是MyBufferedReader就是對FileReader的增強。這中方式叫做裝飾設計模式。

  解釋:當想要對已有的對象進行功能增強時,可以定義類,將已有對象傳入,基於已有對象的功能,並提供加強功能,

     那麼自定義的該類,就稱爲裝飾類。

 看下面代碼的小例子

package com.jbit.zhkk;

/**
 * 裝飾設計模式: 當想要對已有的對象進行功能增強時, 可以定義類,將已有的對象傳入,基於已有的功能,並提供加強功能。 那麼自定義的該類稱爲裝飾類。
 * 裝飾類通常會通過構造方法接受被裝飾的對象。 並基於被裝飾的對象的功能,提供更強的功能。
 * 
 * @author Administrator
 * 
 */
public class Test4 {
	public static void main(String[] args) {
		Person p = new Person();
		SuperPerson sp = new SuperPerson(p);
		sp.superEat();
	}
}

class Person {
	public void eat() {
		System.out.println("吃飯");
	}
}

class SuperPerson {
	private Person p;

	public SuperPerson(Person p) {
		this.p = p;
	}

	public void superEat() {
		System.out.println("甜點");
		p.eat();
		System.out.println("香菸");
	}
}

裝飾模式比繼承要靈活,避免了繼承體系臃腫。

而且降低了類與類之間的關係。

裝飾類因爲增強已有的對象,具備的功能和已有的是相同的,只不過提供了更強的功能,所以裝飾類和被裝飾類通常是都屬於一個體系中的。
  LineNumberReader的使用

   


import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.LineNumberReader;

public class Test9 {
	public static void main(String[] args) throws Exception {
		FileReader fr = new FileReader("c:\\Test8.java");//創建文本流對象
		LineNumberReader lnr = new LineNumberReader(fr);//LineNumberReader 關聯文本流
		String line = null;
		//讀取一行
		while ((line = lnr.readLine()) != null) {
			System.out.println(lnr.getLineNumber() + "::" + line);
		}
		lnr.close();//關閉,其實也就是fr.close()
	}
}



模擬一個帶行號的緩衝區對象

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Test9 {
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("c:\\Test8.java");// 讀取流對象
		MyLineReaderDemo frd = new MyLineReaderDemo(fr);// 自定義的模擬一個帶行號的緩衝區類對象
		String line = null;
		while ((line = frd.readLine()) != null) {
			System.out.println(frd.getLineNum() + ":" + line);
		}
		frd.close();
	}
}

/**
 * /自定義的模擬一個帶行號的緩衝區類
 * 
 * @author Administrator
 * 
 */
class MyLineReaderDemo {
	private int linenum;// 當前行號
	private FileReader fr;// 文本讀取流

	// 構造函數關聯讀取流
	public MyLineReaderDemo(FileReader fr) {
		this.fr = fr;
	}

	// 得到行號
	public int getLineNum() {
		return linenum;
	}

	// 讀取一行
	public String readLine() throws IOException {
		linenum++;// 讀取一行 行號加一
		StringBuilder sb = new StringBuilder();// 字符串追加器,把一行的數據放到sb中。
		int ch = 0;
		// 一個行的結束就是\r\n
		while ((ch = fr.read()) != -1) {
			if ((char) ch == '\r') {
				continue;// 讀到\r繼續讀取
			}
			if ((char) ch == '\n') {
				return sb.toString();// 讀取\n返回字符串
			} else {
				sb.append((char) ch);
			}
		}
		if (sb.length() != 0) {// 如果沒有\r\n說明讀取到了結尾行,直接返回sb
			return sb.toString();
		}
		return null;
	}

	/**
	 * 設置開始行號
	 * 
	 * @param linenum
	 */
	public void setlineNum(int linenum) {
		this.linenum = linenum;
	}

	// 關閉流,其實就是讀取流關閉
	public void close() throws IOException {
		fr.close();
	}
}


 

優化後的代碼是

 

package com.jbit.zhkk;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Test6 {
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("c:\\Test8.java");
		MyLineReaderDemo frd = new MyLineReaderDemo(fr);
		String line = null;
		while ((line = frd.readLine()) != null) {
			System.out.println(frd.getLineNum() + ":" + line);
		}
		frd.close();
	}
}
/**
 * 這裏可以繼承自定義的讀取緩衝區
 * @author Administrator
 *
 */
class MyLineReaderDemo extends MyBufferedReader {
	private int linenum;

	public MyLineReaderDemo(FileReader fr) {
		super(fr);//調用父類的構造函數,都是FileReader對象
	}

	public int getLineNum() {
		return linenum;
	}

	public String readLine() throws IOException {
		linenum++;
		return super.myReadLine();//代碼重複調用父類的myReadLine()就可
	}

	public void setlineNum(int linenum) {
		this.linenum = linenum;
	}

	public void close() throws IOException {
		super.myClose();
	}
}



 鍵盤錄入

 

import java.io.IOException;
import java.io.InputStream;

public class Test9 {
	public static void main(String[] args) throws IOException {
		InputStream in = System.in;
		StringBuilder sb = new StringBuilder();
		while (true) {
			int ch = in.read();
			String s = null;
			if ((char) ch == '\r') {// 讀到\r繼續下一次讀取
				continue;
			}
			if ((char) ch == '\n') {// 讀到\n如果不是自定義結束標記的話,打印輸出
				s = sb.toString();
				if (s == "over") {// 自定義over結束標記
					break;
				}
				System.out.println(s);// 打印
				sb.delete(0, sb.length());// 這裏一定要重新清除,否則會自動追加到sb中。
			} else {
				sb.append((char) ch);// 如果沒有讀取到換行標記就追加
			}
		}
	}
}



以上的例子,其實就是讀一行的原理,也就是readLine方法。

能不能直接用readLine方法來完成鍵盤錄入的一行數據的讀取呢?

readLine方法是BufferedReader類的方法,而鍵盤錄入的read方法是字節流InputStream的方法

能不能將字節流轉成字符流在使用字符流緩衝區的ReadLine方法呢?

package com.jbit.zhkk;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Test9 {
	public static void main(String[] args) throws IOException {
		// 獲取鍵盤錄入對象
		InputStream in = System.in;
		// 將字節流對象轉換成字符流對象,使用轉換流。InputStreamReader
		InputStreamReader isr = new InputStreamReader(in);
		// 爲了提高效率,將字符流進行緩衝區技術的搞笑操作,使用BufferedReader
		BufferedReader bufr = new BufferedReader(isr);
		String line = null;
		while (((line = bufr.readLine())) != null) {
			if ("over".equals(line)) {
				break;
			}
			System.out.println(line.toUpperCase());
		}
	}
}


 writer是寫,把文件寫出去,文件以字節形式存在的,而錄入的都是字符,Reader這就是字符

從JDK文檔中可以知道FileOutputStream是OutputStream 的直接子類,FileInputStream也是InputStream的直接子類,但是在字符流文件中的兩個操作類卻有一些特殊,FileWriter並不直接是Writer的子類,而是OutputStreamWriter的子類,而FileReader也不直接是Reader的子類,是InputStreamReader的子類,那麼從這兩個類的繼承關係就可以清楚地發現,不管是使用字節流還是字符流實際上最終都是以字節的形式操作輸入/輸出流的。

package com.jbit.zhkk;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

public class Test9 {
	public static void main(String[] args) throws IOException {
		// 獲取鍵盤錄入對象
		InputStream in = System.in;
		// 將字節流對象轉換成字符流對象,使用轉換流。InputStreamReader
		InputStreamReader isr = new InputStreamReader(in);
		// 爲了提高效率,將字符流進行緩衝區技術的高效操作,使用BufferedReader
		BufferedReader bufr = new BufferedReader(isr);
		OutputStream out=System.out;
		OutputStreamWriter osw=new OutputStreamWriter(out);
		BufferedWriter bufw=new BufferedWriter(osw);
		String line = null;
		while (((line = bufr.readLine())) != null) {
			if ("over".equals(line)) {
				break;
			}
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();//字符輸出流內部有緩衝區,把數據緩衝了,刷新
		}
	}
}

簡寫後的格式爲

 

package com.jbit.zhkk;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class Test9 {
	public static void main(String[] args) throws IOException {
		// // 獲取鍵盤錄入對象
		// InputStream in = System.in;
		// // 將字節流對象轉換成字符流對象,使用轉換流。InputStreamReader
		// InputStreamReader isr = new InputStreamReader(in);
		// // 爲了提高效率,將字符流進行緩衝區技術的搞笑操作,使用BufferedReader
		// BufferedReader bufr = new BufferedReader(isr);
		// 鍵盤錄入最常見寫法
		BufferedReader bufr = new BufferedReader(new InputStreamReader(
				System.in));
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(
				System.out));
		// OutputStream out=System.out;
		// OutputStreamWriter osw=new OutputStreamWriter(out);
		// BufferedWriter bufw=new BufferedWriter(osw);
		String line = null;
		while (((line = bufr.readLine())) != null) {
			if ("over".equals(line)) {
				break;
			}
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
	}
}


流對象的操作規律:

    最痛苦的就是流對象有很多,不知道該用哪一個。

通過三個明確來完成。

1,明確源和目的

      源:輸入流。 InputStream Reader

      目的:輸出流。OutputStream Writer

 2,操作的數據是否是存文本

         是:字符流

        不是:字節流

3,當體系明確後,再明確要使用哪個具體的對象。

          通過設備來進行區分:

           源 設備:內存,硬盤,鍵盤

          目的設備:內存,硬盤,控制檯。

io所有流的總結概述

首先是四大基本抽象流:字節流:InputStream、OutputStream,字符流:Reader、Writer;輸入流:InputStream、Reader,輸出流:
OutputStream、Writer;後面的所有流都是這四個的子類;

文件流:FileInputStream、FileOutputStream,FileReader、FileWriter,文件流算是四大基本抽象流的最初級實現類,前面兩個是字節
流,可以用於任何格式文件的讀寫(因爲文件的最基本存儲形式就是字節數據),後面兩個是字符流,只能用來處理文本文件;

緩衝流:字節流:BufferedInputStream、BufferedOutputStream,字符流:BufferedReader、BufferedWriter,這四個流用的是裝飾設計
模式,在使用時要接收其它的流對象,比如文件流;同文件流一樣,前面兩個流可用於任何類型的文件讀寫,後面兩個流主要用於文本文件
的讀寫,由於這四個流在建立對象後內部會自建緩衝區,所以讀寫的效率比較高,尤其是BufferedReader中的readLine()方法讀取文本文
件特別合適,可以整行整行的讀取,遇到換行符算是一行的結束,但是它不會返回換行符,所以需要在調用write()方法後用newLine()
方法新建換行符;

數據流:DataInputStream、DataOutputStream:用於基本類型數據的讀寫,採用裝飾設計模式,構造方法的形參是流對象;

標準輸入輸出流:java.lang.System下的兩個流,public static final InputStream in:標準輸入流,此流已打開並準備提供輸入數據。
通常,此流對應於鍵盤輸入或者由主機環境或用戶指定的另一個輸入源。public static final PrintStream out:標準輸出流,此流已打
開並準備接受輸出數據。通常,此流對應於顯示器輸出或者由主機環境或用戶指定的另一個輸出目標。

轉換流:輸入流InputStreamReader,將讀取的字節數據轉換爲字符數據,輸出流:OutputStreamWriter,將字符轉換爲字節輸出,這兩個
流都採用裝飾設計模式,構造方法的形參是流對象,都可以指定轉碼時的編碼表或者使用平臺默認的碼錶;

從鍵盤錄入:BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
輸出到控制檯:法一:BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
法二:PrintWriter pw = new PrintWriter(System.out, true);(PrintWriter流屬於Print流,加上true參數,表示自動刷新緩衝區,無需調用flush方法,
而且這個流中的println方法會自動添加換行符,無需再調用newLine方法)

File類:將用戶傳遞過來的文件名或者文件的路徑封裝爲類對象,然後在對其進行讀寫前進行一系列的判斷:比如exists(),判斷文件或
路徑是否存在,isFile(),判斷是不是文件,isDirectory(),判斷是不是目錄,如果結果爲false,直接讓程序return,這樣做豈不是更
安全!

Print流:PrintStream和PrintWriter,都用於寫出,前者構造方法接收的參數類型爲String文件名、File對象、OutputStream對象,後者
構造方法接收的參數類型爲String文件名、File對象、OutputStream對象以及Writer對象,由於後者接收的參數類型範圍廣,所以其使用的
頻率更高。
public PrintWriter(Writer out, boolean autoFlush):若autoFlush的值爲true,則每次輸出一行後會自動刷新,無需調用flush方法,
否則等遇到輸入結束標誌,纔會在關閉流的時候刷新,但此法僅限於使用println、printf或者format三個方法時有效;
public PrintStream(OutputStream out, boolean autoFlush):功能類似於PrintWriter,但只有使用println方法或者遇到換行符時就會
刷新;

其它流:ByteArrayInputStream:構造函數接收字節數組,也即數據源就是字節數組;
ByteArrayOutputStream:構造函數不需要數據目的地,因爲在該流內部已經封裝了一個字節數組作爲目的地,它會隨着寫入數據的增多而
自動增長,可使用 toByteArray() 和 toString() 獲取數據;
這兩個流因爲並沒有調用底層系統資源,所以close方法無效,類中的方法在關閉此流後仍可被調用,它們也不會拋出IOException;

流操作中的數據源和目的地:
數據源:
鍵盤(System.in)、硬盤(FileInputStream(文件))、內存(ByteArrayInputStream);
數據目的地:
控制檯(System.out)、硬盤(FileOutputStream(文件))、內存(ByteArrayOutputStream);


這衆多的流中,除了最早出場的文件流外,其它的都是裝飾設計模式,構造方法接收的形參都是流對象

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