EOFException異常詳解


最近線上的系統被檢測出有錯誤日志,領導讓我檢查下問題,我就順便了解了下這個異常。

  了解一個類,當然是先去看他的API,EOFException的API如下:

  通過這個API,我們可以得出以下信息:

  • 這是一個IO異常的子類,名字也是END OF FILE的縮寫,當然也表示流的末尾
  • 它在表明一個信息,流已經到末尾了,而大部分做法是以特殊值的形式返回給我們,而不是拋異常

  也就是說這個異常是被主動拋出來的,而不是底層或者編譯器返回給我的,就像NullPointerException或IndexOutOfBoundsException一樣。

  我們先來看InputStream,這個輸入流,當讀到了結尾會怎么樣,看看API介紹:

  可以看到如果到達流的末尾,那么會返回-1,也就是說我們可以根據這個-1來判斷是否到達流的末尾。

  同樣的我們看一下輸入流的包裝類BufferedReader,它有一個讀一行的方法:

 

  也可以發現當讀到流的末尾,通過返回值null來告訴我們到達流的末尾了,也就是說通過返回一個不可能的值來表示到達流的末尾。

  那我們找一個EOFException的例子,在jdk類中就有一個,那就是ObjectInputStream,我寫了一個測試代碼,如下:

復制代碼
package yiwangzhibujian.objectstream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class ObjectStream { public static void main(String[] args) throws Exception { User user1=new User("yiwangzhibujian",27); User user2=new User("laizhezhikezhui",24); ByteArrayOutputStream bos=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bos); oos.writeObject(user1); oos.writeObject(user2); oos.writeObject(null); byte[] data = bos.toByteArray(); ByteArrayInputStream bis=new ByteArrayInputStream(data); ObjectInputStream ois=new ObjectInputStream(bis); System.out.println(ois.readObject()); System.out.println(ois.readObject()); System.out.println(ois.readObject()); System.out.println(ois.readObject()); } } class User implements Serializable{ private static final long serialVersionUID = 1L; public String name; public int age; public User(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "User [name=" + name + ", age=" + age + "]"; } }
復制代碼

  控制台輸出結果為:

復制代碼
User [name=yiwangzhibujian, age=27]
User [name=laizhezhikezhui, age=24] null Exception in thread "main" java.io.EOFException at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2608) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1319) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) at yiwangzhibujian.objectstream.ObjectStream.main(ObjectStream.java:28)
復制代碼

  可以感覺到EOFException的用意,因為我們可以往流中放入null值,所以我們沒法找到一個不可能的值來表示到達流的末尾,所以只能通過拋異常的方式來告訴用戶到達末尾了,相應的拋異常部分的源碼如下:

復制代碼
byte peekByte() throws IOException { int val = peek(); if (val < 0) { throw new EOFException(); } return (byte) val; }
復制代碼

  也就是說,ObjectInputStream在讀取具體的對象之前會優先讀取一個標識符,它通過是否能讀到符號來判斷是否到達流的末尾,因為再底層的流會通過返回-1來表明,然后ObjectInputStream會根據標識符來判斷讀到的是什么類型,因為ObjectOutputStream 在寫入內容的時候會這么做:

  所以說ObjectInputStream可以自己判斷流是否到達末尾,但是它無法告訴我們,我們不能替代他們讀取這個標記,不然ObjectInputStream將識別不了下一個內容的實際類型。

  所以呢,對於這種異常的一般解決方法就是,捕獲,可以記錄日志,也可以不做處理,捕獲異常以后,把之前讀到的數據進行后續的處理就可以了,因為那就是所以的數據。還有就是如果打算記錄日志,不要把它的堆棧信息打印出來,容易給人以錯覺。畢竟EOFException實質上只是一個消息而已。

  當然拋異常的做法還是有一些偏激,但是當ObjectInputStream在不知道讀取對象數量的情況下,確實無法判斷是否讀完,除非你把之前寫入對象流的數量記錄下來。所以說出現這個異常時就認真分析一下,這個異常是不是代表一個信息。

 

  希望我對這個問題的理解,能幫助到遇到同樣問題的人。

 

需求:  *1、創建54張撲克牌,將撲克牌寫入文件card.txt  *2、將寫入的文件內容,讀取出來,可以生成相對應的54張撲克牌  *3、保證撲克牌可以調用自己的方法 

 遇到的問題以及解決方法:

1.序列化的問題:你要創建的對象在流中傳輸,必須將此類對象進行序列化,就是implements Serializable接口

2.EOFException的問題: 你從文件中讀取對象的時候,如何判斷是否讀取完畢。jvm會給拋出EOFException,表示的是,文件中對象讀取完畢。所以呢,你在判斷是否讀取結束的時候,捕獲掉這個異常就可以,是捕獲不是拋出。

重要的說三次,是捕獲,捕獲,捕獲!

代碼如下:

 

 

  1.  
    package day02;
  2.  
     
  3.  
    import java.io.EOFException;
  4.  
    import java.io.File;
  5.  
    import java.io.FileInputStream;
  6.  
    import java.io.FileNotFoundException;
  7.  
    import java.io.FileOutputStream;
  8.  
    import java.io.IOException;
  9.  
    import java.io.ObjectInputStream;
  10.  
    import java.io.ObjectOutputStream;
  11.  
    import java.util.ArrayList;
  12.  
    import java.util.List;
  13.  
     
  14.  
    /**
  15.  
    *1、創建54張撲克牌,將撲克牌寫入文件card.txt
  16.  
    *2、將寫入的文件內容,讀取出來,可以生成相對應的54張撲克牌
  17.  
    *3、保證撲克牌可以調用自己的方法
  18.  
    */
  19.  
    public class Exercis {
  20.  
    public static void main(String[] args) throws FileNotFoundException, IOException {
  21.  
    ObjectOutputStream os= new ObjectOutputStream(new FileOutputStream(new File("./card.txt")));
  22.  
    List<Card> lists= new ArrayList<Card>();
  23.  
    for(int i=Card.THREE;i<=Card.TWO;i++){
  24.  
    lists.add( new Card(Card.HEITAO,i));
  25.  
    lists.add( new Card(Card.HONGTAO,i));
  26.  
    lists.add( new Card(Card.MEIHUA,i));
  27.  
    lists.add( new Card(Card.FANGKUAI,i));
  28.  
     
  29.  
    }
  30.  
    lists.add( new Card(Card.JOKER,Card.BLACK));
  31.  
    lists.add( new Card(Card.JOKER,Card.COLOR));
  32.  
    for(Card c : lists){
  33.  
    os.writeObject(c);
  34.  
    }
  35.  
    ObjectInputStream is= new ObjectInputStream(new FileInputStream(new File("./card.txt")));
  36.  
    while(true){
  37.  
    Object o = null;
  38.  
    try {
  39.  
    o = is.readObject();
  40.  
    if(o instanceof Card){
  41.  
    System.out.println(o);
  42.  
    }
  43.  
    } catch (ClassNotFoundException e) {
  44.  
    // TODO Auto-generated catch block
  45.  
    e.printStackTrace();
  46.  
    } catch(EOFException e){
  47.  
    System.out.println( "讀寫完畢!");
  48.  
    os.close();
  49.  
    is.close();
  50.  
    break;
  51.  
    }
  52.  
    }
  53.  
    }
  54.  
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM