day27_ IO異常的處理丶特殊IO流丶Properties集合

IO異常的處理

JDK7前處理

在jdk1.7之前使用try catch finally 處理流中的異常



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

/*
    在jdk1.7之前使用try catch finally 處理流中的異常
    格式:
        try{
            可能會產出異常的代碼
        }catch(異常類變量 變量名){
            異常的處理邏輯
        }finally{
            一定會指定的代碼
            資源釋放
        }
 */
public class Demo01TryCatch {
    public static void main(String[] args) {
        //提高變量fw的作用域,讓finally可以使用
        //變量在定義的時候,可以沒有值,但是使用的時候必須有值
        //fw = new FileWriter("09_IOAndProperties\\g.txt",true); 執行失敗,fw沒有值,fw.close會報錯
        FileWriter fw = null;
        try{
            //可能會產出異常的代碼
            fw = new FileWriter("w:\\09_IOAndProperties\\g.txt",true);
            for (int i = 0; i <10 ; i++) {
                fw.write("HelloWorld"+i+"\r\n");
            }
        }catch(IOException e){
            //異常的處理邏輯
            System.out.println(e);
        }finally {
            //一定會指定的代碼
            //創建對象失敗了,fw的默認值就是null,null是不能調用方法的 ,
會拋出NullPointerException,需要增加一個判斷,不是null在把資源釋放
            if(fw!=null){
                try {
                    //fw.close方法聲明拋出了IOException異常對象,
所以我們就的處理這個異常對象,要麼throws,要麼try catch
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

JDK7的新特性

在try的後邊可以增加一個(),在括號中可以定義流對象,那麼這個流對象的作用域就在try中有效,try中的代碼執行完畢,會自動把流對象釋放,不用寫finally。



import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
 
    格式:
        try(定義流對象;定義流對象....){
            可能會產出異常的代碼
        }catch(異常類變量 變量名){
            異常的處理邏輯
        }
 */
public class Demo02JDK7 {
    public static void main(String[] args) {
        try(//1.創建一個字節輸入流對象,構造方法中綁定要讀取的數據源
            FileInputStream fis = new FileInputStream("c:\\1.jpg");
            //2.創建一個字節輸出流對象,構造方法中綁定要寫入的目的地
            FileOutputStream fos = new FileOutputStream("d:\\1.jpg");){

            //可能會產出異常的代碼
            //一次讀取一個字節寫入一個字節的方式
            //3.使用字節輸入流對象中的方法read讀取文件
            int len = 0;
            while((len = fis.read())!=-1){
                //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中
                fos.write(len);
            }

        }catch (IOException e){
            //異常的處理邏輯
            System.out.println(e);
        }


    }
}

JDK9新特性

  • try的前邊可以定義流對象
  • 在try後邊的()中可以直接引入流對象的名稱(變量名)
  • 在try代碼執行完畢之後,流對象也可以釋放掉,不用寫finally
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    格式:
        A a = new A();
        B b = new B();
        try(a,b){
            可能會產出異常的代碼
        }catch(異常類變量 變量名){
            異常的處理邏輯
        }
 */
public class Demo03JDK9 {
    public static void main(String[] args) throws IOException {
        //1.創建一個字節輸入流對象,構造方法中綁定要讀取的數據源
        FileInputStream fis = new FileInputStream("c:\\1.jpg");
        //2.創建一個字節輸出流對象,構造方法中綁定要寫入的目的地
        FileOutputStream fos = new FileOutputStream("d:\\1.jpg");

        try(fis;fos){
            //一次讀取一個字節寫入一個字節的方式
            //3.使用字節輸入流對象中的方法read讀取文件
            int len = 0;
            while((len = fis.read())!=-1){
                //4.使用字節輸出流中的方法write,把讀取到的字節寫入到目的地的文件中
                fos.write(len);
            }
        }catch (IOException e){
            System.out.println(e);
        }

        //fos.write(1);//Stream Closed

    }
}

IO特殊操作流

打印流 PrintStream

PrintStream extends OutputStream,平時我們在控制檯打印輸出,是調用 print 方法和 println 方法完成的,這兩個方法都來自於 java.io.PrintStream 類,該類能夠方便地打印各種數據類型的值,是一種便捷的輸出方式。 PrintStream 爲其他輸出流添加了功能,使它們能夠方便地打印各種數據值表示形式。

PrintStream特點:

  • 只負責數據的輸出,不負責數據的讀取
  • 與其他輸出流不同,PrintStream 永遠不會拋出 IOException
  • 有特有的方法,print,println

構造方法:

  • PrintStream(File file):輸出的目的地是一個文件
  • PrintStream(OutputStream out):輸出的目的地是一個字節輸出流
  • PrintStream(String fileName) :輸出的目的地是一個文件路徑

繼承自父類的成員方法:

  • public void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。
  • public void flush() :刷新此輸出流並強制任何緩衝的輸出字節被寫出。
  • public void write(byte[] b):將 b.length字節從指定的字節數組寫入此輸出流。
  • public void write(byte[] b, int off, int len) :從指定的字節數組寫入 len字節,從偏移量 off開始輸出到此輸出流。
  • public abstract void write(int b) :將指定的字節輸出流。

注意:

  • 如果使用繼承自父類的write方法寫數據,那麼查看數據的時候會查詢編碼表 97->a
  • 如果使用自己特有的方法print/println方法寫數據,寫的數據原樣輸出 97->97
import java.io.FileNotFoundException;
import java.io.PrintStream;


public class Demo01PrintStream {
    public static void main(String[] args) throws FileNotFoundException {
        //System.out.println("HelloWorld");

        //創建打印流PrintStream對象,構造方法中綁定要輸出的目的地
        PrintStream ps = new PrintStream("10_IO\\print.txt");
        //如果使用繼承自父類的write方法寫數據,那麼查看數據的時候會查詢編碼表 97->a
        ps.write(97);
        //如果使用自己特有的方法print/println方法寫數據,寫的數據原樣輸出 97->97
        ps.println(97);
        ps.println(8.8);
        ps.println('a');
        ps.println("HelloWorld");
        ps.println(true);

        //釋放資源
        ps.close();
    }
}

可以改變輸出語句的目的地(打印流的流向), 輸出語句,默認在控制檯輸出

package com.itheima.demo05.PrintStream;

import java.io.FileNotFoundException;
import java.io.PrintStream;

/*

   使用System.setOut方法改變輸出語句的目的地改爲參數中傳遞的打印流的目的地
        static void setOut(PrintStream out)
          重新分配“標準”輸出流。
 */
public class Demo02PrintStream {
    public static void main(String[] args) throws FileNotFoundException {
        System.out.println("我是在控制檯輸出");

        PrintStream ps = new PrintStream("10_IO\\目的地是打印流.txt");
        System.setOut(ps);//把輸出語句的目的地改變爲打印流的目的地
        System.out.println("我在打印流的目的地中輸出");
        ps.close();
    }
}

對象序列化流

序列化概述 :Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該 對象的數據 對象的 類型 和 對象中存儲的屬性 等信息。字節序列寫出到文件之後,相當於文件中持久保存了一個對象的信息。反之,該字節序列還可以從文件中讀取回來,重構對象,對它進行反序列化對象的數據 對象的類型 對象中 存儲的數據 信息,都可以用來在內存中創建對象。看圖理解序列化:

                      

ObjectOutputStream

概述:

  • java.io.ObjectOutputStream extends OutputStream
  • ObjectOutputStream:對象的序列化流
  • 作用:把對象以流的方式寫入到文件中保存

構造方法:

  • ObjectOutputStream(OutputStream out) 創建寫入指定 OutputStream 的 ObjectOutputStream。參數: OutputStream out:字節輸出流

特有的成員方法:

  • void writeObject(Object obj) 將指定的對象寫入 ObjectOutputStream。

注意事項

  • 一個對象要想被序列化,該對象所屬的類必須必須實現Serializable 接口
  • Serializable是一個標記接口,實現該接口,不需要重寫任何方法

凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量:

  • private static final long serialVersionUID;
  • serialVersionUID用來表明類的不同版本間的兼容性。簡言之,其目的是以序列化對象 進行版本控制,有關各版本反序列化時是否兼容。
  • 如果類沒有顯示定義這個靜態常量,它的值是Java運行時環境根據類的內部細節自 動生成的。若類的實例變量做了修改,serialVersionUID 可能發生變化。故建議, 顯式聲明。

簡單來說,Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗 證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的 serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同 就認爲是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異 常。(InvalidCastException)

使用步驟:

  1. 創建ObjectOutputStream對象,構造方法中傳遞字節輸出流
  2. 使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中
  3. 釋放資源
定義Person 類
package demo01;

import java.io.Serializable;

/*
    序列化和反序列化的時候,會拋出NotSerializableException沒有序列化異常
    類通過實現 java.io.Serializable 接口以啓用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化。
    Serializable接口也叫標記型接口
        要進行序列化和反序列化的類必須實現Serializable接口,就會給類添加一個標記
        當我們進行序列化和反序列化的時候,就會檢測類上是否有這個標記
            有:就可以序列化和反序列化
            沒有:就會拋出 NotSerializableException異常
    static關鍵字:靜態關鍵字
        靜態優先於非靜態加載到內存中(靜態優先於對象進入到內存中)
        被static修飾的成員變量不能被序列化的,序列化的都是對象
        private static int age;
        oos.writeObject(new Person("小美女",18));
        Object o = ois.readObject();
        Person{name='小美女', age=0}

    transient關鍵字:瞬態關鍵字
        被transient修飾成員變量,不能被序列化
        private transient int age;
        oos.writeObject(new Person("小美女",18));
        Object o = ois.readObject();
        Person{name='小美女', age=0}

 */
public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    //private static int age;
    //private transient int age;
    public int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", 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;
    }
}

ObjectInputStream

ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復爲對象。

使用序列化流,永久保存數據

package demo01;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/*
    java.io.ObjectOutputStream extends OutputStream
    ObjectOutputStream:對象的序列化流
    作用:把對象以流的方式寫入到文件中保存

    構造方法:
        ObjectOutputStream(OutputStream out) 創建寫入指定 OutputStream 的 ObjectOutputStream。
        參數:
            OutputStream out:字節輸出流
    特有的成員方法:
        void writeObject(Object obj) 將指定的對象寫入 ObjectOutputStream。

    使用步驟:
        1.創建ObjectOutputStream對象,構造方法中傳遞字節輸出流
        2.使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中
        3.釋放資源
 */
public class Demo01ObjectOutputStream {
    public static void main(String[] args) throws IOException {
        //1.創建ObjectOutputStream對象,構造方法中傳遞字節輸出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\person.txt"));
        //2.使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中
        oos.writeObject(new Person("小美女",18));
        //3.釋放資源
        oos.close();
    }
}

使用反序列化流,讀取數據

package demo01;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/*
    java.io.ObjectInputStream extends InputStream
    ObjectInputStream:對象的反序列化流
    作用:把文件中保存的對象,以流的方式讀取出來使用

    構造方法:
        ObjectInputStream(InputStream in) 創建從指定 InputStream 讀取的 ObjectInputStream。
        參數:
            InputStream in:字節輸入流
    特有的成員方法:
        Object readObject() 從 ObjectInputStream 讀取對象。

    使用步驟:
        1.創建ObjectInputStream對象,構造方法中傳遞字節輸入流
        2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件
        3.釋放資源
        4.使用讀取出來的對象(打印)

     readObject方法聲明拋出了ClassNotFoundException(class文件找不到異常)
     當不存在對象的class文件時拋出此異常
     反序列化的前提:
        1.類必須實現Serializable
        2.必須存在類對應的class文件
 */
public class Demo02ObjectInputStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //1.創建ObjectInputStream對象,構造方法中傳遞字節輸入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\person.txt"));
        //2.使用ObjectInputStream對象中的方法readObject讀取保存對象的文件
        Object o = ois.readObject();
        //3.釋放資源
        ois.close();
        //4.使用讀取出來的對象(打印)
        System.out.println(o);
        Person p = (Person)o;
        System.out.println(p.getName()+p.getAge());
    }

}

屬性集(Properties類 )

概述 :java.util.Properties 繼承於 Hashtable ,來表示一個持久的屬性集。它使用鍵值結構存儲數據,每個鍵及其 對應值都是一個字符串。該類也被許多Java類使用,比如獲取系統屬性時, System.getProperties 方法就是返回 一個 Properties 對象。

構造方法
  • public Properties() :創建一個空的屬性列表。

基本的存儲方法

  • public Object setProperty(String key, String value) : 保存一對屬性。
  • public String getProperty(String key) :使用此屬性列表中指定的鍵搜索屬性值。
  • public Set<String> stringPropertyNames() :所有鍵的名稱的集合。

方法演示:



import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

/*
    java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v>
    Properties 類表示了一個持久的屬性集。Properties 可保存在流中或從流中加載。
    Properties集合是一個唯一和IO流相結合的集合
        可以使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲
        可以使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用

    屬性列表中每個鍵及其對應值都是一個字符串。
        Properties集合是一個雙列集合,key和value默認都是字符串
 */
public class Demo01Properties {
    public static void main(String[] args) throws IOException {
       
    }

    /*
        可以使用Properties集合中的方法load,把硬盤中保存的文件(鍵值對),讀取到集合中使用
        void load(InputStream inStream)
        void load(Reader reader)
        參數:
            InputStream inStream:字節輸入流,不能讀取含有中文的鍵值對
            Reader reader:字符輸入流,能讀取含有中文的鍵值對
        使用步驟:
            1.創建Properties集合對象
            2.使用Properties集合對象中的方法load讀取保存鍵值對的文件
            3.遍歷Properties集合
        注意:
            1.存儲鍵值對的文件中,鍵與值默認的連接符號可以使用=,空格(其他符號)
            2.存儲鍵值對的文件中,可以使用#進行註釋,被註釋的鍵值對不會再被讀取
            3.存儲鍵值對的文件中,鍵與值默認都是字符串,不用再加引號
     */
    private static void show03() throws IOException {
        //1.創建Properties集合對象
        Properties prop = new Properties();
        //2.使用Properties集合對象中的方法load讀取保存鍵值對的文件
        prop.load(new FileReader("09_IOAndProperties\\prop.txt"));
        //prop.load(new FileInputStream("09_IOAndProperties\\prop.txt"));
        //3.遍歷Properties集合
        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            String value = prop.getProperty(key);
            System.out.println(key+"="+value);
        }
    }

    /*
        可以使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲
        void store(OutputStream out, String comments)
        void store(Writer writer, String comments)
        參數:
            OutputStream out:字節輸出流,不能寫入中文
            Writer writer:字符輸出流,可以寫中文
            String comments:註釋,用來解釋說明保存的文件是做什麼用的
                    不能使用中文,會產生亂碼,默認是Unicode編碼
                    一般使用""空字符串

        使用步驟:
            1.創建Properties集合對象,添加數據
            2.創建字節輸出流/字符輸出流對象,構造方法中綁定要輸出的目的地
            3.使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲
            4.釋放資源
     */
    private static void show02() throws IOException {
        //1.創建Properties集合對象,添加數據
        Properties prop = new Properties();
        prop.setProperty("趙麗穎","168");
        prop.setProperty("迪麗熱巴","165");
        prop.setProperty("古力娜扎","160");

        //2.創建字節輸出流/字符輸出流對象,構造方法中綁定要輸出的目的地
        //FileWriter fw = new FileWriter("09_IOAndProperties\\prop.txt");

        //3.使用Properties集合中的方法store,把集合中的臨時數據,持久化寫入到硬盤中存儲
        //prop.store(fw,"save data");

        //4.釋放資源
        //fw.close();

        prop.store(new FileOutputStream("09_IOAndProperties\\prop2.txt"),"");
    }

    /*
        使用Properties集合存儲數據,遍歷取出Properties集合中的數據
        Properties集合是一個雙列集合,key和value默認都是字符串
        Properties集合有一些操作字符串的特有方法
            Object setProperty(String key, String value) 調用 Hashtable 的方法 put。
            String getProperty(String key) 通過key找到value值,此方法相當於Map集合中的get(key)方法
            Set<String> stringPropertyNames() 
返回此屬性列表中的鍵集,其中該鍵及其對應值是字符串,此方法相當於Map集合中的keySet方法
     */
    private static void show01() {
        //創建Properties集合對象
        Properties prop = new Properties();
        //使用setProperty往集合中添加數據
        prop.setProperty("趙麗穎","168");
        prop.setProperty("迪麗熱巴","165");
        prop.setProperty("古力娜扎","160");
        //prop.put(1,true);

        //使用stringPropertyNames把Properties集合中的鍵取出,存儲到一個Set集合中
        Set<String> set = prop.stringPropertyNames();

        //遍歷Set集合,取出Properties集合的每一個鍵
        for (String key : set) {
            //使用getProperty方法通過key獲取value
            String value = prop.getProperty(key);
            System.out.println(key+"="+value);
        }
    }
}

PropertiesIO流相結合的方法

IO流結合的方法 ​​​​​​​

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