天天看點

IO流-File,位元組流,緩沖流

1.1 IO概述

回想之前寫過的程式,資料都是在記憶體中,一旦程式運作結束,這些資料都沒有了,等下次再想使用這些資料,可是已經沒有了。那怎麼辦呢?能不能把運算完的資料都儲存下來,下次程式啟動的時候,再把這些資料讀出來繼續使用呢?其實要把資料持久化存儲,就需要把記憶體中的資料存儲到記憶體以外的其他持久化裝置(硬碟、CD光牒、U盤等 ROM)上。

當需要把記憶體中的資料存儲到持久化裝置上這個動作稱為輸出(寫)Output操作。

當把持久裝置上的資料讀取到記憶體中的這個動作稱為輸入(讀)Input操作。

是以我們把這種輸入和輸出動作稱為IO操作。

IO流-File,位元組流,緩沖流

1.2 IO流流向分類

按照流向分:輸入流與輸出流,每個IO流對象均要綁定一個IO資源

分類關系如下:

位元組輸入流 InputStream的抽象類

  FileInputStream 操作檔案的位元組輸入流

位元組輸出流 OutputStream的抽象類

  FileOutputStream 操作檔案的位元組輸出流

按照傳輸方式:分為位元組流和字元流

    字元流  按照字元的方式讀寫 

    位元組流  按照位元組的方式讀寫

1.3 一切均為位元組

在資料傳輸過程中,一切資料(文本、圖像、聲音等)最終存儲的均為一個個位元組,即二進制數字。是以資料傳輸過程中使用二進制資料可以完成任意資料的傳遞。

第1章 File

在我們作業系統中,資料都儲存在檔案中,而檔案存放相應的檔案夾中。那麼Java中是如何描述這些的呢?

1.1 File類的出現

打開API,搜尋File類。閱讀其描述:File檔案和目錄路徑名的抽象表示形式。即,Java中把檔案或者目錄(檔案夾)都封裝成File對象。也就是說如果我們要去操作硬碟上的檔案,或者檔案夾隻要找到File這個類即可。那麼我們就要研究研究File這個類中都有那些功能可以操作檔案或者檔案夾呢?

1.2 File類的構造方法

IO流-File,位元組流,緩沖流

通過構造方法建立File對象,我們進行代碼示範:

public static void main(String[] args) {
        //方法1:
        String filePath = "G:\\FileTest\\file1.txt";
        File file = new File(filePath);
        System.out.println(file);
        // 方法2:将parent封裝成file對象。
        File dir = new File("G:\\FileTest");
        File file2 = new File(dir, "hello.java");
        //方法3:
        File file3 = new File("G:\\FileTest", "hello.java");
    }      

1.3 File類的方法

建立完了File對象之後,那麼File類中都有如下常用方法

public static void main(String[] args) throws IOException {
        String dirPath = "g:\\TestFiles";
        //String dirPath = "g:\\TestFile";//注意java建立檔案夾和檔案名不要包含file,可能存在bug,建立不成功
        String filePath = "G:\\TestFiles\\file1.txt";
        File dir = new File("g:\\TestFiles");
        boolean b1=dir.mkdir();//建立一個空的新檔案夾(前提是該檔案不存在)
        File file = new File(filePath);
        boolean b2=file.createNewFile();//建立一個空的新檔案(前提是該檔案不存在)注意,要保證該路徑下所有的檔案夾都已經存在或者在此之前已經建立
        // 建立檔案,如果檔案不存在,建立 true 如果檔案存在,則不建立 false。 如果路徑錯誤,IOException。
        String absPath=file.getAbsolutePath();//擷取檔案全路徑
        String path=file.getPath();//擷取我們構造檔案的時候的路徑(也就是File構造方法裡面我們傳遞的字元串)
        String name=file.getName();//擷取檔案名
        String parent=file.getParent();//擷取父檔案夾檔案名
        boolean isfile=file.isFile();//判斷是不是檔案(如果檔案不存在傳回false)
        boolean isdir=file.isDirectory();//判斷是不是檔案夾(如果檔案夾不存在傳回false)
        boolean canread=file.canRead();//判斷是否可讀
        boolean canwrite=file.canWrite();//判斷是否可寫
        long lenth=file.length();//傳回檔案的長度
        boolean b3=file.exists();//判斷檔案是否存在
        boolean b4 = file.delete();//删除檔案操作--删除成功傳回true,檔案不存在傳回false-----注意:不去資源回收筒。慎用------
        //删除目錄時,如果目錄中有内容,無法直接删除傳回false。隻有将目錄中的内容都删除後,保證該目錄為空。這時這個目錄才可以删除。
        boolean b5 = dir.delete();
        System.out.println("b1="+b1);
        System.out.println(absPath);
        System.out.println(path);
        System.out.println(name);
        System.out.println(parent);
        System.out.println(isfile);
        System.out.println(isdir);
        System.out.println(canread);
        System.out.println(canwrite);
        System.out.println(lenth);
        System.out.println(b3);
        System.out.println(b4);
        System.out.println(b5);      
//    1.1 listFiles()和list()方法介紹      
     File dir0=new File("g://files");
        File dir1=new File("g://files//dir1");
        File dir2=new File("g://files//dir2");
        File f1=new File("g://files//dir2//test1.txt");
        File f2=new File("g://files//dir2//test2.txt");
        File f3=new File("g://files//dir1//test3.txt");
        if(!dir1.exists()) {
            dir1.mkdirs();
        }
        if(!dir2.exists()) {
            dir2.mkdirs();
        }
        if(!f1.exists()) {
            f1.createNewFile();
        }
        if(!f2.exists()) {
            f2.createNewFile();
        }
        if(!f3.exists()) {
            f3.createNewFile();
        }
        String arg1[]=dir0.list();//擷取的是目錄下的目前的檔案以及檔案夾的名稱。
        for(String s: arg1) {
            System.out.println(s);
        }
        File f[]=dir0.listFiles();//擷取目錄下目前檔案以及檔案對象,隻要拿到了檔案對象,那麼就可以擷取其中想要的資訊
        for(File ff:f) {
            System.err.println(ff);
        }      
}      

第2章 位元組流

既然一切資料都是位元組,那麼位元組流如何操作呢,那麼接下來我們進行位元組流的學習.

2.1 位元組輸出流OutputStream

OutputStream此抽象類,是表示輸出位元組流的所有類的超類。操作的資料都是位元組,定義了輸出位元組流的基本共性功能方法。

輸出流中定義都是寫write方法;

  2.1.1 FileOutputStream類

OutputStream有很多子類,其中子類FileOutputStream可用來寫入資料到檔案。

FileOutputStream類,即檔案輸出流,是用于将資料寫入 File的輸出流。

IO流-File,位元組流,緩沖流

構造方法:

IO流-File,位元組流,緩沖流

代碼示範:

public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //需求:将資料寫入到檔案中。
        //建立存儲資料的檔案。
        File f1=new File("g://files//dir2//test1.txt");
        File f2=new File("g://files//dir2//test2.txt");
        File f3=new File("g://files//dir2//test3.txt");
        //建立一個用于操作檔案的位元組輸出流對象。一建立就必須明确資料存儲目的地。
        //輸出流目的是檔案,會自動建立。如果檔案存在,則覆寫。
        FileOutputStream fs1=new FileOutputStream(f1);
        FileOutputStream fs2=new FileOutputStream(f2,true);//第二個參數true辨別不是覆寫,而是續寫
        FileOutputStream fs3=new FileOutputStream(f3);
        byte b[]="123我很開心".getBytes();
        //調用父類的write方法
        fs1.write(b);//将b全部寫出
        fs2.write(b,2,4);//将b裡面索引在2-4的内容寫出(3我很)
        fs3.write(10);//這個方法有待研究
        //重新整理此輸出流并強制寫出所有緩沖的輸出位元組
        fs1.flush();
        //關閉流資源
        fs1.close();
        
        fs2.flush();
        fs2.close();
        fs3.flush();
        fs3.close();
    }      

  2.2.1 FileInputStream類

InputStream有很多子類,其中子類FileInputStream可用來讀取檔案内容。

FileInputStream 從檔案系統中的某個檔案中獲得輸入位元組。

IO流-File,位元組流,緩沖流
IO流-File,位元組流,緩沖流

  2.2.2 FileInputStream類讀取資料read方法(隻讀純英文,有空介紹一下讀中文問題)

在讀取檔案中的資料時,調用read方法,實作從檔案中讀取資料

IO流-File,位元組流,緩沖流
public static void main(String[] args) throws Exception {
        File f1=new File("g://files//dir2//test1.txt");
        FileInputStream fis1=new FileInputStream(f1);
        //讀取資料。使用 read();一次讀一個位元組。
        int n;
        while((n=fis1.read())!=-1) {
            System.out.println((char)n);
        }
        fis1.close();
    }      

  2.2.3 讀取資料read(byte[])方法

在讀取檔案中的資料時,調用read方法,每次隻能讀取一個,太麻煩了,于是我們可以定義數組作為臨時的存儲容器,這時可以調用重載的read方法,一次可以讀取多個字元。

public static void main(String[] args) throws Exception {
        File f1=new File("g://files//dir2//test1.txt");
        FileInputStream fis1=new FileInputStream(f1);
        /*
         * 示範第二個讀取方法, read(byte[]);
         */
        int n=0;
        byte b[]=new byte[1024];//長度可以定義成1024的整數倍。
        while((n=fis1.read(b))!=-1) {
            System.out.println(new String(b,0,n));
        }
        fis1.close();
    }      

  2.3.1 複制檔案

原理;讀取一個已有的資料,并将這些讀到的資料寫入到另一個檔案中。

public class CopyFileTest {
    public static void main(String[] args) throws IOException {
        //1,明确源和目的。
        File srcFile = new File("c:\\YesDir\test.JPG");
        File destFile = new File("copyTest.JPG");
        
        //2,明确位元組流 輸入流和源相關聯,輸出流和目的關聯。
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        
        //3, 使用輸入流的讀取方法讀取位元組,并将位元組寫入到目的中。
        int ch = 0;
        while((ch=fis.read())!=-1){
            fos.write(ch);
        }
        //4,關閉資源。
        fos.close();
        fis.close();
    }
}      

上述代碼輸入流和輸出流之間是通過ch這個變量進行資料交換的。

上述複制檔案有個問題,每次都從源檔案讀取一個,然後在寫到指定檔案,接着再讀取一個字元,然後再寫一個,一直這樣下去。效率極低。

  2.3.2臨時數組方式複制檔案

上述代碼複制檔案效率太低了,并且頻繁的從檔案讀資料,和寫資料,能不能一次多把檔案中多個資料都讀進内容中,然後在一次寫出去,這樣的速度一定會比前面代碼速度快。

public class CopyFileByBufferTest {
    public static void main(String[] args) throws IOException {
        File srcFile = new File("c:\\YesDir\test.JPG");
        File destFile = new File("copyTest.JPG");
        // 明确位元組流 輸入流和源相關聯,輸出流和目的關聯。
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        //定義一個緩沖區。
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fis.read(buf)) != -1) {
            fos.write(buf, 0, len);// 将數組中的指定長度的資料寫入到輸出流中。
        }
        // 關閉資源。
        fos.close();
        fis.close();
    }
}      

第3章 字元流

經過前面的學習,我們基本掌握的檔案的讀寫操作,在操作過程中位元組流可以操作所有資料,可是當我們操作的檔案中有中文字元,并且需要對中文字元做出處理時怎麼辦呢?

在IO開發過程中,我們傳輸最頻繁的資料為字元,而以位元組方式傳輸字元需要每次将字元串轉換成位元組再處理,而且也喪失了程式員對資料内容的判斷(因為程式員隻認識字元,不認識位元組)。是以,為了讓程式員友善對字元進行操作,Java提供了專門以字元作為操作機關的類——字元流,其底層仍然為位元組流。

顯然,字元流隻能操作字元,無法操作其他資料,如聲音、視訊等。

代碼示例:

/**
     * 字元流
     * @throws IOException
     */
    public static void zifuliu() throws IOException {
        FileReader fr=new FileReader("g://files//dir2//test1.txt");
        BufferedReader br=new BufferedReader(fr);
        FileWriter fw=new FileWriter("g://files//dir2//test4.txt");
        BufferedWriter bw=new BufferedWriter(fw);
        String content="";
        while((content=br.readLine())!=null) {
            bw.write(content+"\r\n");
        }
        fw.flush();
        fr.close();
        bw.close();
        br.close();
    }
          

第4章 緩沖流

在我們學習位元組流與字元流的時候,大家都進行過讀取檔案中資料的操作,讀取資料量大的檔案時,讀取的速度會很慢,很影響我們程式的效率,那麼,我想提高速度,怎麼辦?

Java中提高了一套緩沖流,它的存在,可提高IO流的讀寫速度

緩沖流,根據流的分類分為位元組緩沖流與字元緩沖流。

4.1 位元組緩沖流

位元組緩沖流根據流的方向,共有2個

l 寫入資料到流中,位元組緩沖輸出流 BufferedOutputStream

l 讀取流中的資料,位元組緩沖輸入流 BufferedInputStream

它們的内部都包含了一個緩沖區,通過緩沖區讀寫,就可以提高了IO流的讀寫速度

  4.1.1位元組緩沖輸出流BufferedOutputStream

通過位元組緩沖流,進行檔案的讀寫操作 寫資料到檔案的操作  

l 構造方法

public BufferedOutputStream(OutputStream out)建立一個新的緩沖輸出流,以将資料寫入指定的底層輸出流。 

public class BufferedOutputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        
        //寫資料到檔案的方法
        write();
    }

    /*
     * 寫資料到檔案的方法
     * 1,建立流
     * 2,寫資料
     * 3,關閉流
     */
    private static void write() throws IOException {
        //建立基本的位元組輸出流
        FileOutputStream fileOut = new FileOutputStream("abc.txt");
        //使用高效的流,把基本的流進行封裝,實作速度的提升
        BufferedOutputStream out = new BufferedOutputStream(fileOut);
        //2,寫資料
        out.write("hello".getBytes());
        //3,關閉流
        out.close();
    }
}      

  4.1.2 位元組緩沖輸入流 BufferedInputStream

剛剛我們學習了輸出流實作了向檔案中寫資料的操作,那麼,現在我們完成讀取檔案中資料的操作

public BufferedInputStream(InputStream in)

/*
     * 從檔案中讀取資料
     * 1,建立緩沖流對象
     * 2,讀資料,列印
     * 3,關閉
     */
    private static void read() throws IOException {
        //1,建立緩沖流對象
        FileInputStream fileIn = new FileInputStream("abc.txt");
        //把基本的流包裝成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn);
        //2,讀資料
        int ch = -1;
        while ( (ch = in.read()) != -1 ) {
            //列印
            System.out.print((char)ch);
        }
        //3,關閉
        in.close();
    }      

         4.3.3 複制單級檔案夾

/* 
 * 資料源:e:\\demo
 * 目的地:e:\\test
 * 
 * 分析:
 *         A:封裝目錄
 *         B:擷取該目錄下的所有文本的File數組
 *         C:周遊該File數組,得到每一個File對象
 *         D:把該File進行複制
 */
public class CopyFolderDemo {
    public static void main(String[] args) throws IOException {
        // 封裝目錄
        File srcFolder = new File("e:\\demo");
        // 封裝目的地
        File destFolder = new File("e:\\test");
        // 如果目的地檔案夾不存在,就建立
        if (!destFolder.exists()) {
            destFolder.mkdir();
        }

        // 擷取該目錄下的所有文本的File數組
        File[] fileArray = srcFolder.listFiles();

        // 周遊該File數組,得到每一個File對象
        for (File file : fileArray) {
            // System.out.println(file);
            // 資料源:e:\\demo\\e.mp3
            // 目的地:e:\\test\\e.mp3
            String name = file.getName(); // e.mp3
            File newFile = new File(destFolder, name); // e:\\test\\e.mp3

            copyFile(file, newFile);
        }
    }

    private static void copyFile(File file, File newFile) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                file));
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(newFile));

        byte[] bys = new byte[1024];
        int len = 0;
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
        }

        bos.close();
        bis.close();
    }
}      

第5章 轉換流

5.1 OutputStreamWriter類

查閱OutputStreamWriter的API介紹,OutputStreamWriter 是字元流通向位元組流的橋梁:可使用指定的字元編碼表,将要寫入流中的字元編碼成位元組。它的作用的就是,将字元串按照指定的編碼表轉成位元組,再使用位元組流将這些位元組寫出去。

/**
     * 轉換流
     * @throws Exception 
     */
    public static void zhuanhuanliu() throws Exception {
        FileOutputStream fs=new FileOutputStream("g://files//dir2//test1.txt");
        //建立可以把字元轉成位元組的轉換流對象,并指定編碼
        OutputStreamWriter osw=new OutputStreamWriter(fs,"utf-8");
        //調用轉換流,把文字寫出去,其實是寫到轉換流的高效區中
        osw.write("我是字元流轉換成位元組流然後寫進的");//寫入高效區。
        osw.flush();
        osw.close();
        fs.close();
    }      

OutputStreamWriter流對象,它到底如何把字元轉成位元組輸出的呢?

其實在OutputStreamWriter流中維護自己的高效區,當我們調用OutputStreamWriter對象的write方法時,會拿着字元到指定的碼表中進行查詢,把查到的字元編碼值轉成位元組數存放到OutputStreamWriter高效區中。然後再調用重新整理功能,或者關閉流,或者高效區存滿後會把高效區中的位元組資料使用位元組流寫到指定的檔案中。

5.2 InputStreamReader類

查閱InputStreamReader的API介紹,InputStreamReader 是位元組流通向字元流的橋梁:它使用指定的字元編碼表讀取位元組并将其解碼為字元。它使用的字元集可以由名稱指定或顯式給定,或者可以接受平台預設的字元集。

/**
     * 轉換流2.
     * @throws IOException 
     */
    public static void zhuanhuanliu2() throws IOException {
        FileInputStream fs=new FileInputStream("g://files//dir2//test1.txt");
        /*    下面本注釋内的代碼在沒有使用轉換流的情況下雖然可以讀取中文,但是列印出來是亂碼的
         *  byte b[]=new byte[1024];
            int n=0;
            while((n=fs.read(b))!=-1) {
            System.out.println(new String(b,0,n));
        }
        */
        //下面通過轉換流讀取進來的漢字是正确的
        //InputStreamReader isr=new InputStreamReader(fs);//這樣建立對象,會用本地預設碼表讀取,将會發生錯誤解碼的錯誤
        InputStreamReader isr=new InputStreamReader(fs,"utf-8");
        int n=0;
        while((n=isr.read())!=-1) {
            System.out.println((char)n);
        }
        isr.close();
        fs.close();
    }      

5.3 轉換流和子類差別

發現有如下繼承關系:

Writer 字元輸出流

  |- OutputStreamWriter   轉換流(字元流—>位元組流)(屬于字元輸出流, 可以指定字元編碼表,用來寫入資料到檔案)

    |--FileWriter 操作檔案中字元輸出流,采用預設的字元編碼表

Reader 字元輸入流

  |- InputStreamReader: 轉換流(位元組流à字元流)(屬于字元輸入流,可以指定字元編碼表,用來從檔案中讀資料)

    |--FileReader操作檔案中字元輸入流,采用預設的字元編碼表

父類和子類的功能有什麼差別呢?

OutputStreamWriter和InputStreamReader是字元和位元組的橋梁:也可以稱之為字元轉換流。字元轉換流原理:位元組流+編碼表。

FileWriter和FileReader:作為子類,僅作為操作字元檔案的便捷類存在。當操作的字元檔案,使用的是預設編碼表時可以不用父類,而直接用子類就完成操作了,簡化了代碼。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//預設字元集。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字元集。

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

這三句代碼的功能是一樣的,其中第三句最為便捷。

注意:一旦要指定其他編碼時,絕對不能用子類,必須使用字元轉換流。什麼時候用子類呢?

條件:

1、操作的是檔案。2、使用預設編碼。

第6章 序列化流與反序列化流

用于從流中讀取對象的操作流 ObjectInputStream   稱為 反序列化流

用于向流中寫入對象的操作流 ObjectOutputStream   稱為 序列化流

l 特點:用于操作對象。可以将對象寫入到檔案中,也可以從檔案中讀取對象。

6.1 對象序列化流ObjectOutputStream

ObjectOutputStream 将 Java 對象的基本資料類型和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀取(重構)對象。通過在流中使用檔案可以實作對象的持久存儲。

注意:隻能将支援 java.io.Serializable 接口的對象寫入流中

IO流-File,位元組流,緩沖流
IO流-File,位元組流,緩沖流
public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        /*
         * 将一個對象存儲到持久化(硬碟)的裝置上。
         */
        writeObj();//對象的序列化。
    }
    public static void writeObj() throws IOException {
        //1,明确存儲對象的檔案。
        FileOutputStream fos = new FileOutputStream("tempfile\\obj.object");
        //2,給操作檔案對象加入寫入對象功能。
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //3,調用了寫入對象的方法。
        oos.writeObject(new Person("wangcai",20));
        //關閉資源。
        oos.close();
    }
}      

person類代碼:

public class Person implements Serializable {
    private String name;
    private int age;
    public Person() {
        super();
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}      

6.2 對象反序列化流ObjectInputStream

ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本資料和對象進行反序列化。支援 java.io.Serializable接口的對象才能從流讀取。

IO流-File,位元組流,緩沖流
IO流-File,位元組流,緩沖流
public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        readObj();//對象的反序列化。
    }
    public static void readObj() throws IOException, ClassNotFoundException {
        
        //1,定義流對象關聯存儲了對象檔案。
        FileInputStream fis = new FileInputStream("tempfile\\obj.object");
        
        //2,建立用于讀取對象的功能對象。
        ObjectInputStream ois = new ObjectInputStream(fis);
        
        Person obj = (Person)ois.readObject();
        
        System.out.println(obj.toString());
        
    }
}      

6.3 序列化接口

當一個對象要能被序列化,這個對象所屬的類必須實作Serializable接口。否則會發生異常NotSerializableException異常。

同時當反序列化對象時,如果對象所屬的class檔案在序列化之後進行的修改,那麼進行反序列化也會發生異常InvalidClassException。發生這個異常的原因如下:

  l 該類的序列版本号與從流中讀取的類描述符的版本号不比對

  l 該類包含未知資料類型

  l 該類沒有可通路的無參數構造方法

Serializable标記接口。該接口給需要序列化的類,提供了一個序列版本号。serialVersionUID. 該版本号的目的在于驗證序列化的對象和對應類是否版本比對。

l 代碼修改如下,修改後再次寫入對象,讀取對象測試

public class Person implements Serializable {
    //給類顯示聲明一個序列版本号。
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    public Person() {
        super();
        
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}      

6.4 瞬态關鍵字transient

當一個類的對象需要被序列化時,某些屬性不需要被序列化,這時不需要序列化的屬性可以使用關鍵字transient修飾。隻要被transient修飾了,序列化時這個屬性就不會被序列化了。

同時靜态修飾也不會被序列化,因為序列化是把對象資料進行持久化存儲,而靜态的屬于類加載時的資料,不會被序列化。

public class Person implements Serializable {
    /*
     * 給類顯示聲明一個序列版本号。
     */
    private static final long serialVersionUID = 1L;
    private static String name;
    private transient/*瞬态*/ int age;
    
    public Person() {
        super();
        
    }
    
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}      

第7章 列印流

7.1 列印流的概述

列印流添加輸出資料的功能,使它們能夠友善地列印各種資料值表示形式.

列印流根據流的分類:

  l 位元組列印流 PrintStream

  l 字元列印流 PrintWriter

l 方法:

  void print(String str): 輸出任意類型的資料,

  void println(String str): 輸出任意類型的資料,自動寫入換行操作

/**
     * 列印流
     * 
     * @throws Exception
     */
    public static void dayinliu() throws Exception {
        /* 
         * 需求:把指定的資料,寫入到printFile.txt檔案中
         * 分析:
         *     1,建立流
         *     2,寫資料
         *     3,關閉流
         */
        //1, 建立流
        // PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"));
        PrintWriter out = new PrintWriter("g://files//dir2//test5.txt");
        // 2,寫資料
        for (int i = 0; i < 5; i++) {
            out.println("helloWorld");
        }
        // 3,關閉流
     out.flush

        out.close();
    }      

第8章 Properties類

8.1 Properties類介紹

Properties 類表示了一個持久的屬性集。Properties 可儲存在流中或從流中加載。屬性清單中每個鍵及其對應值都是一個字元串。

特點:

1、Hashtable的子類,map集合中的方法都可以用。

2、該集合沒有泛型。鍵值都是字元串。

3、它是一個可以持久化的屬性集。鍵值可以存儲到集合中,也可以存儲到持久化的裝置(硬碟、U盤、CD光牒)上。鍵值的來源也可以是持久化的裝置。

4、有和流技術相結合的方法。

IO流-File,位元組流,緩沖流

l load(InputStream)  把指定流所對應的檔案中的資料,讀取出來,儲存到Propertie集合中

l load(Reader)  

l store(OutputStream,commonts)把集合中的資料,儲存到指定的流所對應的檔案中,參數commonts代表對描述資訊

l Store(Writer,comments);

5.成員方法:

 * public Object setProperty(String key, String value)調用 Hashtable 的方法 put。

 * public Set<String> stringPropertyNames()傳回此屬性清單中的鍵集,

 * public String getProperty(String key)用指定的鍵在此屬性清單中搜尋屬性

/*
 * 
 * Properties集合,它是唯一一個能與IO流互動的集合
 * 
 * 需求:向Properties集合中添加元素,并周遊
 * 
 * 方法:
 * public Object setProperty(String key, String value)調用 Hashtable 的方法 put。
 * public Set<String> stringPropertyNames()傳回此屬性清單中的鍵集,
 * public String getProperty(String key)用指定的鍵在此屬性清單中搜尋屬性
 */
public class PropertiesDemo01 {
    public static void main(String[] args) {
        //建立集合對象
        Properties prop = new Properties();
        //添加元素到集合
        //prop.put(key, value);
        prop.setProperty("周迅", "張學友");
        prop.setProperty("李小璐", "賈乃亮");
        prop.setProperty("楊幂", "劉恺威");
        
        //System.out.println(prop);//測試的使用
        //周遊集合
        Set<String> keys = prop.stringPropertyNames();
        for (String key : keys) {
            //通過鍵 找值
            //prop.get(key)
            String value = prop.getProperty(key);
            System.out.println(key+"==" +value);
        }
    }
}      

8.2 将集合中内容存儲到檔案

需求:使用Properties集合,完成把集合内容存儲到IO流所對應檔案中的操作

分析:

1,建立Properties集合

2,添加元素到集合

3,建立流

4,把集合中的資料存儲到流所對應的檔案中

stroe(Writer,comments)

store(OutputStream,commonts)

把集合中的資料,儲存到指定的流所對應的檔案中,參數commonts代表對描述資訊

5,關閉流

public class PropertiesDemo02 {
    public static void main(String[] args) throws IOException {
        //1,建立Properties集合
        Properties prop = new Properties();
        //2,添加元素到集合
        prop.setProperty("周迅", "張學友");
        prop.setProperty("李小璐", "賈乃亮");
        prop.setProperty("楊幂", "劉恺威");
        
        //3,建立流
        FileWriter out = new FileWriter("prop.properties");
        //4,把集合中的資料存儲到流所對應的檔案中
        prop.store(out, "save data");
        //5,關閉流
        out.close();
    }
}      

8.3 讀取檔案中的資料,并儲存到集合

需求:從屬性集檔案prop.properties 中取出資料,儲存到集合中

1,建立集合

2,建立流對象

3,把流所對應檔案中的資料 讀取到集合中

load(InputStream)  把指定流所對應的檔案中的資料,讀取出來,儲存到Propertie集合中

load(Reader)  

public class PropertiesDemo03 {
    public static void main(String[] args) throws IOException {
        //1,建立集合
        Properties prop = new Properties();
        //2,建立流對象
        FileInputStream in = new FileInputStream("prop.properties");
//FileReader in = new FileReader("prop.properties");
        //3,把流所對應檔案中的資料 讀取到集合中
        prop.load(in);
        //4,關閉流
        in.close();
        //5,顯示集合中的資料
        System.out.println(prop);
        
    }
}