天天看點

黑馬程式員—IO操作

---------------------- android教育訓練、java教育訓練、期待與您交流! ----------------------

  學習日志完成于11年12月20日

  今天是自學進階的第二天,用了一天的時間,重新學習了Java IO,東西太多了,腦子都有點大了,但是Java IO是Java SE中非常重要的一塊知識點,是以多花些時間來鞏固掌握也就必須的,呵呵,又是充實的一天,自我鼓勵一下,加油!

  下面是我今天的學習筆記:

1、IO流概述:Java對資料的操作是通過流的方式,IO(InputStream/OutputStream)流用來處理裝置之間的資料傳輸。

流按操作資料的不同分為兩種:位元組流和字元流。位元組流的抽象父類:InputStream 、OutputStream,字元流的抽象父類:Reader、Writer。(位元組流都有自己預設的編碼)

2、字元輸入輸出流

1).檔案輸出流FileWriter

要求:在硬碟上,建立一個檔案并寫入一些文字資料。

import java.io.*;

class  FileWriterDemo{

         public static void main(String[] args) throws IOException {

                   //建立一個FileWriter對象。該對象一被初始化就必須要明确被操作的檔案。

                   //而且該檔案會被建立到指定目錄下。如果該目錄下已有同名檔案,将被覆寫。

                   //其實該步就是在明确資料要存放的目的地。

                   FileWriter fw = new FileWriter("demo.txt");

                   //調用write方法,将字元串寫入到流中。

                   fw.write("abcdefg");

                   //重新整理流對象中的緩沖中的資料。

                   //将資料刷到目的地中。

                   //fw.flush();

                   //關閉流資源,但是關閉之前會重新整理一次内部的緩沖中的資料。

                   //将資料刷到目的地中。

                   //和flush差別:flush重新整理後,流可以繼續使用,close重新整理後,會将流關閉。

                   fw.close();

         }

}

在IO流的操作中,會發生IO異常,可用try...catch..finally方式來處理。标準處理方式:

import java.io.*;

class  FileWriterDemo2{

         public static void main(String[] args) {

                   FileWriter fw = null;  //在外邊建立引用,在try内進行初始化

                   try{

                            fw = new FileWriter("demo.txt");

                            fw.write("abcdefg");

                   }catch (IOException e){

                            System.out.println("catch:"+e.toString());

                   }finally{                //在finally中對流進行關閉

                            try{

                                     if(fw!=null)     //對IO對象進行空判斷,提高代碼的健壯性

                                               fw.close();                                    

                            }catch (IOException e){

                                     System.out.println(e.toString());

                            }

                   }                

         }

}

在建立初始化流對象時,可傳遞一個true參數,代表不覆寫已有的檔案,并将已有檔案的末尾處進行資料續寫,若續寫時實作換行,可用”\n”,如:

FileWriter  fw = new FileWriter("demo.txt",true);

fw.write("\n你好!謝謝!");

2).文本檔案讀取流FileWriter

讀取方式一: 讀取單個字元,int read()

import java.io.*;

class  FileReaderDemo{

         public static void main(String[] args) throws IOException{

                   //建立一個檔案讀取流對象,和指定名稱的檔案相關聯。

                  //要保證該檔案是已經存在的,如果不存在,會發生異常FileNotFoundException

                   FileReader fr = new FileReader("demo.txt");

                   //調用讀取流對象的read方法。

                   //read():一次讀一個字元,而且會自動往下讀。如果讀到末尾,則傳回-1

                   int ch = 0;

                   while((ch=fr.read())!=-1){

                            System.out.println("ch="+(char)ch);

                   }

                   fr.close();

         }

}

讀取方式二:将字元讀入數組,int  read(char[])  傳回的是讀到字元個數。

import java.io.*;

class FileReaderDemo2 {

         public static void main(String[] args) throws IOException{

                   FileReader fr = new FileReader("demo.txt");

                   char[] buf = new char[1024];  //定義一個字元數組,用于存儲讀到字元。

                   int num = 0;

                   while((num=fr.read(buf))!=-1){

                            System.out.println(new String(buf,0,num));

                   }

                   fr.close();

         }

}

3).綜合練習:将c盤一個文本檔案複制到d盤(複制原理)

import java.io.*;

public class CopyText {

    //從C槽全部讀取完之後,再寫入D盤

         public static void main(String[] args) throws IOException{

                   copy2();

         }

         public static void copy2(){

                   FileWriter fw = null;

                   FileReader fr = null;

                   try{

                            fw = new FileWriter("SystemDemocopy.txt");

                            fr = new FileReader("SystemDemo.java");

                            char[] buf = new char[1024];

                            int len = 0;

                            while((len=fr.read(buf))!=-1){

                                     fw.write(buf,0,len);

                            }

                   }catch (IOException e){

                            throw new RuntimeException("讀寫失敗");

                   }finally {

                            if(fr!=null)

                                     try{

                                               fr.close();

                                     }catch (IOException e){}

                            if(fw!=null)

                                     try{

                                               fw.close();

                                     }catch (IOException e)

                                     {}

                   }

         }

//從C槽讀一個字元,就往D盤寫一個字元。

         public static void copy1() throws IOException{

                   FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");

                   FileReader fr = new FileReader("RuntimeDemo.java");

                   int ch = 0;

                   while((ch=fr.read())!=-1){

                            fw.write(ch);

                   }       

                   fw.close();

                   fr.close();

         }

}

3、字元流的緩沖區

作用:緩沖區的出現提高了對資料的讀寫效率。

對應類:BufferedWriter、BufferedReader,緩沖區結合流才可以使用

1).字元輸出流緩沖區:BufferedWriter

import java.io.*;

public class  BufferedWriterDemo {

         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();    //該緩沖區中提供了一個跨平台的換行符newLine()。

                            bufw.flush();

                   }

//記住:隻要用到緩沖區,就要記得重新整理。

                   bufw.close();    //其實關閉緩沖區,就是在關閉緩沖區中的流對象。

         }

}

2).字元輸入流緩沖區:BufferedReader(僅此類提供讀取一行的方法readLine())

import java.io.*;

public class BufferedReaderDemo01{

         public static void main(String args[]) throws IOException{

                   FileReader fr=new FileReader("bufWriter.txt");

                   BufferedReader bufr=new BufferedReader(fr);  //将字元讀取流對象作為參數傳遞給緩沖對象的構造函數。

                   String str=null;

                   while((str=bufr.readLine())!=null){    //readLine()一次讀取一行,當傳回null時,表示讀到檔案末尾。

                            System.out.println(str);

                   }

        Bufr.close();

         }

}

3).綜合練習:通過緩沖區複制一個.java檔案。

import java.io.*;

class  CopyTextByBuf {

         public static void main(String[] args) {

                   BufferedReader bufr = null;

                   BufferedWriter bufw = null;

                   try{

                            bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));

                            bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));

                            String line = null;

                            while((line=bufr.readLine())!=null){  //readLine()隻讀取換行符之前的字元内容

                                     bufw.write(line);

                                     bufw.newLine();

                                     bufw.flush();

                            }

                   }catch (IOException e){

                            throw new RuntimeException("讀寫失敗");

                   }finally{

                            try{

                                     if(bufr!=null)

                                               bufr.close();

                            }catch (IOException e){

                                     throw new RuntimeException("讀取關閉失敗");

                            }

                            try{

                                     if(bufw!=null)

                                               bufw.close();

                            }catch (IOException e){

                                     throw new RuntimeException("寫入關閉失敗");

                            }

                   }

         }

}

readLine方法原理:無論是讀取一行還是讀取多個字元,其實最終都是在硬碟上一個一個讀取,是以最終使用的還是read方法一次讀一個。通過下列字元之一即可認為某行已終止:換行 ('\n')、回車 ('\r') 或回車後直接跟着換行。

4、裝飾設計模式

當想要對已有的對象進行功能增強時,可以定義類,将已有對象傳入,基于已有的功能,并提供加強功能。

那麼自定義的該類稱為裝飾類。裝飾類通常會通過構造方法接收被裝飾的對象,并基于被裝飾的對象的功能,提供更強的功能。

裝飾與繼承的差別

MyReader    //專門用于讀取資料的類

         |--MyTextReader    //專門用于讀取文本資料的類

                   |--MyBufferTextReader    //通過引入緩沖,提高讀取資料的效率

         |--MyMediaReader  //專門用于讀取媒體資料的類

                   |--MyBufferMediaReader  //通過引入緩沖,提高讀取資料的效率

class MyBufferReader{

         MyBufferReader(MyTextReader text){}

         MyBufferReader(MyMediaReader media){}

}

通過繼承可以使每一個子類都具備緩沖功能,但是這樣的話,繼承體系會變得很複雜,并不利于擴充。

class MyBufferReader extends MyReader{

    private MyReader r;

    MyBufferReader(MyReader r){}

}  

MyReader    //專門用于讀取資料的類。

    |--MyTextReader

    |--MyMediaReader

    |--MyBufferReader

現在優化思想,單獨描述一下緩沖内容:将需要被緩沖的對象,傳遞進來。也就是,誰需要被緩沖,誰就作為參數傳遞給緩沖區。這樣繼承體系就變得很簡單,進而優化了體系結構。

裝飾模式比繼承要靈活,避免了繼承體系的臃腫。而且降低了類于類之間的關系。

裝飾類因為增強已有對象,具備的功能和已有的是相同的,隻不過提供了更強功能。是以裝飾類和被裝飾類通常是都屬于一個體系中(繼承同一個類或接口)的。

5、位元組輸入/輸出流  InputStream/OutputStream (可以操作多種媒體檔案)

綜合範例:位元組輸入輸出的基本操作

import java.io.*;

class  FileStream{

         public static void main(String[] args) throws IOException{

                   readFile_3();

         }

         public static void readFile_3() throws IOException{  //讀取方式3,但對于大檔案,不建議使用此方法

                   FileInputStream fis = new FileInputStream("fos.txt");

                   byte[] buf = new byte[ fis.available() ];  //定義一個剛剛好的緩沖區,不用在循環了。

                   fis.read(buf);

                   System.out.println(new String(buf));

                   fis.close();

         }

         public static void readFile_2()throws IOException{  //讀取方式2(常用)

                   FileInputStream fis = new FileInputStream("fos.txt");

                   byte[] buf = new byte[1024];

                   int len = 0;

                   while((len=fis.read(buf))!=-1){  //read(buf)以位元組數組方式來讀取

                            System.out.println(new String(buf,0,len));

                   }

                   fis.close();

         }

         public static void readFile_1()throws IOException{  //讀取方式1(常用)

                   FileInputStream fis = new FileInputStream("fos.txt");

                   int ch = 0;

                   while((ch=fis.read())!=-1){  //read()一個一個位元組來讀

                            System.out.println((char)ch);

                   }

                   fis.close();

         }

         public static void writeFile()throws IOException{

                   FileOutputStream fos = new FileOutputStream("fos.txt");

                   fos.write("abcde".getBytes());  //将字元串轉換成位元組

                   fos.close();                

         }

}

要求:複制一張圖檔(可使用位元組流的緩沖區BufferedInputStream、BufferedOutputStream,類似于字元流的緩沖區)

import java.io.*;

class  CopyPic{

         public static void main(String[] args) {

                   FileOutputStream fos = null;

                   FileInputStream fis = null;

                   try{

                            fos = new FileOutputStream("2.jpg");

                            fis = new FileInputStream("1.jpg");

                            byte[] buf = new byte[1024];

                            int len = 0;

                            while((len=fis.read(buf))!=-1){

                                     fos.write(buf,0,len);

                            }

                   }catch (IOException e){

                            throw new RuntimeException("複制檔案失敗");

                   }finally{

                            try{

                                     if(fis!=null)

                                               fis.close();

                            }catch (IOException e){

                                     throw new RuntimeException("讀取關閉失敗");

                            }

                            try{

                                     if(fos!=null)

                                               fos.close();

                            }catch (IOException e){

                                     throw new RuntimeException("寫入關閉失敗");

                            }

                   }

         }

}

6、讀取鍵盤錄入

System.out:對應的是标準輸出裝置,控制台

System.in:對應的标準輸入裝置:鍵盤

import java.io.*;

class  ReadIn {

         public static void main(String[] args) throws IOException {

                   InputStream in = System.in;  //擷取錄入鍵盤

                   StringBuilder sb = new StringBuilder();  //可變長度

                   while(true){

                            int ch = in.read();

                            if(ch=='\r')

                                     continue;

                            if(ch=='\n'){

                                     String s = sb.toString();

                                     if("over".equals(s))

                                               break;

                                     System.out.println(s.toUpperCase());  //變成大寫輸出

                                     sb.delete(0,sb.length());

                            }else

                                     sb.append((char)ch);

                   }

         }

}

寫入轉換流:

import java.io.*;

class  TransStreamDemo{

         public static void main(String[] args) throws IOException{

                   BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));   //鍵盤的最常見寫法

        BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

                   String line = null;

                   while((line=bufr.readLine())!=null) {

                            if("over".equals(line))

                                     break;

                            bufw.write(line);

                            bufw.newLine();

                            bufw.flush();

                   }

                   bufr.close();

         }

}

7、列印流

思考:如果現在要想完成一個字元串或者是boolean型或者是字元型的資料輸出使用OutputStream是否友善?

         肯定是不友善的,因為OutputStream中隻能操作位元組資料,是以其他的資料類型很難操作,那麼在Java的IO包中為了解決這種問題增加了兩種類:PrintStream、PrintWriter。

         觀察PrintStream類的構造:public PrintStream(OutputStream out)

         雖然PrintStream是OutputStream的子類,但是在執行個體化的時候依然需要一個OutputStream的對象。

         在PrintStream中定義了一系列的輸出操作,可以友善的完成輸出,那麼這種設計思路就是裝飾設計。

package org.lxh.printstreamdemo;

import java.io.File;

import java.io.FileOutputStream;

import java.io.PrintStream;

public class PrintStreamDemo01 {

    public static void main(String[] args) throws Exception {

        PrintStream out = new PrintStream(new FileOutputStream(new File("d:"

                + File.separator + "test.txt")));

        out.print(1 + " + " + 1 + " = ");

        out.println(1 + 1);

        out.println("Hello World!!!") ;

    }

}

         在開發中由于PrintStream較為好用,是以隻要是輸出就使用列印流完成。

8、Scanner類

      在JDK 1.5之後為了友善輸入,又增加了一個新的類:Scanner,此類并不是在java.io包中定義的,而是在java.util包中定義的。

       使用Scanner可以友善的完成各種位元組輸入流的輸入,構造:public Scanner(InputStream source)

package org.lxh.scandemo;

import java.util.Scanner;

public class ScannerDemo01 {

    public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);  //鍵盤錄入

        System.out.print("請輸入内容:");

        if (scan.hasNext()) { // 現在有内容

            String str = scan.next();

            System.out.println("輸入的内容是:" + str);

        }

    }

}

       在IO操作記住:輸出的時候使用PrintStream,輸入的時候使用Scanner。

---------------------- android教育訓練、java教育訓練、期待與您交流! ----------------------

詳細請檢視:http://edu.csdn.net/heima