IO流上:概述、字符流、緩沖區
一、IO流概述
概述:
IO流簡單來說就是Input和Output流,IO流主要是用來處理設備之間的數據傳輸,java對於數據的操作都是通過流實現,而java用於操作流的對象都在IO包中。
分類:
按操作數據分為:字節流和字符流。 如:Reader和InpurStream
按流向分:輸入流和輸出流。如:InputStream和OutputStream
IO流常用的基類:
* InputStream , OutputStream
字符流的抽象基類:
* Reader , Writer
由上面四個類派生的子類名稱都是以其父類名作為子類的後綴:
如:FileReader和FileInputStream
二、字符流
1. 字符流簡介:
* 字符流中的對象融合了編碼表,也就是系統默認的編碼表。我們的系統一般都是GBK編碼。
* 字符流只用來處理文本數據,字節流用來處理媒體數據。
* 數據最常見的表現方式是文件,字符流用於操作文件的子類一般是FileReader和FileWriter。
2.字符流讀寫:
註意事項:
* 寫入文件後必須要用flush()刷新。
* 用完流後記得要關閉流
* 使用流對象要拋出IO異常
* 定義文件路徑時,可以用“/”或者“\\”。
* 在創建一個文件時,如果目錄下有同名文件將被覆蓋。
* 在讀取文件時,必須保證該文件已存在,否則出異常示例1:在硬盤上創建一個文件,並寫入一些文字數據
- class FireWriterDemo {
- public static void main(String[] args) throws IOException { //需要對IO異常進行處理
- //創建一個FileWriter對象,該對象一被初始化就必須要明確被操作的文件。
- //而且該文件會被創建到指定目錄下。如果該目錄有同名文件,那麽該文件將被覆蓋。
- FileWriter fw = new FileWriter("F:\\1.txt");//目的是明確數據要存放的目的地。
- //調用write的方法將字符串寫到流中
- fw.write("hello world!");
- //刷新流對象緩沖中的數據,將數據刷到目的地中
- fw.flush();
- //關閉流資源,但是關閉之前會刷新一次內部緩沖中的數據。當我們結束輸入時候,必須close();
- fw.write("first_test");
- fw.close();
- //flush和close的區別:flush刷新後可以繼續輸入,close刷新後不能繼續輸入。
- }
- }
示例2:FileReader的reade()方法.
要求:用單個字符和字符數組進行分別讀取
- class FileReaderDemo {
- public static void main(String[] args) {
- characters();
- }
- /*****************字符數組進行讀取*********************/
- private static void characters() {
- try {
- FileReader fr = new FileReader("Demo.txt");
- char [] buf = new char[6];
- //將Denmo中的文件讀取到buf數組中。
- int num = 0;
- while((num = fr.read(buf))!=-1) {
- //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符
- sop(new String(buf,0,num));
- }
- sop(‘\n‘);
- fr.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /*****************單個字母讀取*************************/
- private static void singleReader() {
- try {
- //創建一個文件讀取流對象,和指定名稱的文件關聯。
- //要保證文件已經存在,否則會發生異常:FileNotFoundException
- FileReader fr = new FileReader("Demo.txt");
- //如何調用讀取流對象的read方法?
- //read()方法,一次讀取一個字符,並且自動往下讀。如果到達末尾則返回-1
- int ch = 0;
- while ((ch=fr.read())!=-1) {
- sop((char)ch);
- }
- sop(‘\n‘);
- fr.close();
- /*int ch = fr.read();
- sop("ch=" + (char)ch);
- int ch2 = fr.read();
- sop("ch2=" + (char)ch2);
- //使用結束註意關閉流
- fr.close(); */
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj) {
- System.out.print(obj);
- }
- }
示例3:對已有文件的數據進行續寫
- import java.io.*;
- class FileWriterDemo3 {
- public static void main(String[] args) {
- try {
- //傳遞一個參數,代表不覆蓋已有的數據。並在已有數據的末尾進行數據續寫
- FileWriter fw = new FileWriter("F:\\java_Demo\\day9_24\\demo.txt",true);
- fw.write(" is charactor table?");
- fw.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
練習:
將F盤的一個文件復制到E盤。
思考:
其實就是將F盤下的文件數據存儲到D盤的一個文件中。
步驟:
1.在D盤創建一個文件,存儲F盤中文件的數據。
2.定義讀取流和F:盤文件關聯。
3.通過不斷讀寫完成數據存儲。
4.關閉資源。源碼:
- import java.io.*;
- import java.util.Scanner;
- class CopyText {
- public static void main(String[] args) throws IOException {
- sop("請輸入要拷貝的文件的路徑:");
- Scanner in = new Scanner(System.in);
- String source = in.next();
- sop("請輸入需要拷貝到那個位置的路徑以及生成的文件名:");
- String destination = in.next();
- in.close();
- CopyTextDemo(source,destination);
- }
- /*****************文件Copy*********************/
- private static void CopyTextDemo(String source,String destination) {
- try {
- FileWriter fw = new FileWriter(destination);
- FileReader fr = new FileReader(source);
- char [] buf = new char[1024];
- //將Denmo中的文件讀取到buf數組中。
- int num = 0;
- while((num = fr.read(buf))!=-1) {
- //String(char[] value , int offest,int count) 分配一個新的String,包含從offest開始的count個字符
- fw.write(new String(buf,0,num));
- }
- fr.close();
- fw.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj) {
- System.out.println(obj);
- }
- }
三、緩沖區
1. 字符流的緩沖區:BufferedReader和BufferedWreiter
* 緩沖區的出現時為了提高流的操作效率而出現的.
* 需要被提高效率的流作為參數傳遞給緩沖區的構造函數
* 在緩沖區中封裝了一個數組,存入數據後一次取出
BufferedReader示例:
讀取流緩沖區提供了一個一次讀一行的方法readline,方便對文本數據的獲取。
readline()只返回回車符前面的字符,不返回回車符。如果是復制的話,必須加入newLine(),寫入回車符newLine()是java提供的多平臺換行符寫入方法。
- import java.io.*;
- class BufferedReaderDemo {
- public static void main(String[] args) throws IOException {
- //創建一個字符讀取流流對象,和文件關聯
- FileReader rw = new FileReader("buf.txt");
- //只要將需要被提高效率的流作為參數傳遞給緩沖區的構造函數即可
- BufferedReader brw = new BufferedReader(rw);
- for(;;) {
- String s = brw.readLine();
- if(s==null) break;
- System.out.println(s);
- }
- brw.close();//關閉輸入流對象
- }
- }
BufferedWriter示例:
- import java.io.*;
- class BufferedWriterDemo {
- public static void main(String[] args) throws IOException {
- //創建一個字符寫入流對象
- FileWriter fw = new FileWriter("buf.txt");
- //為了提高字符寫入效率,加入了緩沖技術。
- //只要將需要被提高效率的流作為參數傳遞給緩沖區的構造函數即可
- BufferedWriter bfw = new BufferedWriter(fw);
- //bfw.write("abc\r\nde");
- //bfw.newLine(); 這行代碼等價於bfw.write("\r\n"),相當於一個跨平臺的換行符
- //用到緩沖區就必須要刷新
- for(int x = 1; x < 5; x++) {
- bfw.write("abc");
- bfw.newLine(); //java提供了一個跨平臺的換行符newLine();
- bfw.flush();
- }
- bfw.flush(); //刷新緩沖區
- bfw.close(); //關閉緩沖區,但是必須要先刷新
- //註意,關閉緩沖區就是在關閉緩沖中的流對象
- fw.close(); //關閉輸入流對象
- }
- }
2.裝飾設計模式
裝飾設計模式::::
要求:自定義一些Reader類,讀取不同的數據(裝飾和繼承的區別)
MyReader //專門用於讀取數據的類
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader
如果將他們抽取出來,設計一個MyBufferReader,可以根據傳入的類型進行增強
class MyBufferReader {
MyBufferReader (MyTextReader text) {}
MyBufferReader (MyMediaReader media) {}
MyBufferReader (MyDataReader data) {}
}
但是上面的類拓展性很差。找到其參數的共同類型,通過多態的形式,可以提高拓展性
class MyBufferReader extends MyReader{
private MyReader r; //從繼承變為了組成模式 裝飾設計模式
MyBufferReader(MyReader r) {}
}
優化後的體系:
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader //增強上面三個。裝飾模式比繼承靈活,
避免繼承體系的臃腫。降低類與類之間的耦合性
裝飾類只能增強已有的對象,具備的功能是相同的。所以裝飾類和被裝飾類屬於同一個體系
MyBuffereReader類: 自己寫一個MyBuffereReader類,功能與BuffereReader相同
- class MyBufferedReader1 extends Reader{
- private Reader r;
- MyBufferedReader1(Reader r){
- this.r = r;
- }
- //一次讀一行數據的方法
- public String myReaderline() throws IOException {
- //定義一個臨時容器,原BufferReader封裝的是字符數組。
- //為了演示方便。定義一個StringBuilder容器。最終要將數據變成字符串
- StringBuilder sb = new StringBuilder();
- int ch = 0;
- while((ch = r.read()) != -1)
- {
- if(ch == ‘\r‘)
- continue;
- if(ch == ‘\n‘) //遇到換行符\n,返回字符串
- return sb.toString();
- else
- sb.append((char)ch);
- }
- if(sb.length()!=0) //當最後一行不是以\n結束時候,這裏需要判斷
- return sb.toString();
- return null;
- }
- /*
- 需要覆蓋Reader中的抽象方法close(),read();
- */
- public void close()throws IOException {
- r.close();
- }
- public int read(char[] cbuf,int off, int len)throws IOException { //覆蓋read方法
- return r.read(cbuf,off,len);
- }
- public void myClose() throws IOException{
- r.close();
- }
- }
IO流上:概述、字符流、緩沖區