2014-05-21 42 views
1

我的Java項目有問題。經過多次搜索,我仍然被封鎖。Java - ArrayList序列化的「無效流頭」

我有一個名爲ListFromFile擴展ArrayList類:

public class ListFromFile<T> extends ArrayList<T> implements Serializable { 

    private String listFile; 

    public ListFromFile() { 
     this.listFile = null; 
    } 

    public ListFromFile(String file) { 
     this.listFile = file; 
    } 

    public void loadDataFromFile() { // Deserialize from file 

     try { 
      FileInputStream fileInput = new FileInputStream(this.listFile); 

      if (fileInput.read() == -1) { // If file is empty 
       this.saveDataInToFile(); 
      } else { 
       ObjectInputStream objectInput = new ObjectInputStream(fileInput); 

       this.addAll((ArrayList) objectInput.readObject()); 

       objectInput.close(); 
      } 

      fileInput.close(); 
     } catch (IOException | ClassNotFoundException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void saveDataInToFile() { // Serialize the ArrayList 
     try { 
      FileOutputStream fileOutput = new FileOutputStream(this.listFile, true); 
      ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput); 

      objectOutput.writeObject(this); 

      objectOutput.flush(); 
      objectOutput.close(); 
      fileOutput.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

在我的主類BZ2MServer,我已經創建了一些對象與ListFromFile:

public class BZ2MServer { 

    private static ListFromFile<Specialite> specialites = new ListFromFile<Specialite>("liste_specialites.txt"); 
    private static ListFromFile<Module> modules = new ListFromFile<Module>("liste_modules.txt"); 
    private static ListFromFile<Professeur> professeurs = new ListFromFile<Professeur>("liste_professeurs.txt"); 
    private static ListFromFile<Etudiant> etudiants = new ListFromFile<Etudiant>("liste_etudiants.txt"); 
    private static ListFromFile<Note> notes = new ListFromFile<Note>("liste_notes.txt"); 

    public static void main(String[] args) { 
     specialites.loadDataFromFile(); 
    } 
} 

當應用程序啓動時,它加載列表保存在文件中。這就是爲什麼我在loadDataFromFile()方法中執行saveDataInToFile()。 通過這種方式,文件應該在我們啓動應用程序的第一次包含空的ArrayList。

結果是第一次啓動沒有問題。然而,在此之後,我一直有這樣的來自編譯器:

java.io.StreamCorruptedException: invalid stream header: ED000573 
    at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:804) 
    at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299) 
    at bz2m.list.ListFromFile.loadDataFromFile(ListFromFile.java:31) 
    at bz2m.server.BZ2MServer.main(BZ2MServer.java:22) 

我已在主要測試了這個的BZ2MServer

public static void main(String[] args) { 
    Specialite test = new Specialite(1, "Test"); 

    specialites.add(test2); 

    specialites.saveDataInToFile(); 
} 

然後,我刪除了以前的代碼,用於LoadDataFromFile()得到以前的數據。我得到了錯誤。然後,我刪除了ListFromFile類別中的那個條件:

if (fileInput.read() == -1) { 
    this.saveDataInToFile(); 
} 

它工作。但是,該情況在文件爲空時是必要的。沒有它,如果文件是空的,我得到這個:

java.io.EOFException 
    at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2325) 
    at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2794) 
    at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:801) 
    at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299) 
    at bz2m.list.ListFromFile.loadDataFromFile(ListFromFile.java:31) 
    at bz2m.server.BZ2MServer.main(BZ2MServer.java:22) 

我希望我已經給你所有的信息,你需要幫助我。如果你需要,我可以上傳整個項目(不是很大)。

謝謝!

回答

4

您使用的序列化方法包括一個magic number verification check,它用於確定您的數據是否有效。所以如果它不是它所期望的,它會拋出一個異常,告訴你你的輸入不符合它的序列化標準。

在這種情況下,它預計前兩個字節爲AC ED,後跟版本00 05。你可以在常量列表here中看到它們。

invalid stream header: ED000573表示它收到的輸入的前4個字節是ED 00 05 73。如果你用十六進制查看器打開它,你可能會感到困惑:從0開始的第一個字節確實是AC ED 00 05,那麼問題是什麼?

之所以你的負載方法失敗正是因爲這個檢查你做:

if (fileInput.read() == -1) { 
    this.saveDataInToFile(); 
} 

這讀取一個字節,其遞增文件指針到文件中的第二個字節。現在,當您將流傳遞到ObjectInputStream進行加載時,它將讀取當前指針所在的前4個字節,請參閱ED 00 05 73,然後失敗。您可以通過查看查看器中的下一個字節來驗證它。

如果您要檢查文件是否不爲空,而不是讀取字節,以檢查是否有字節或沒有,只是查詢通道直接長度:

if (fileInput.getChannel().size() == 0) { 
    // empty file 
} 
+0

好,非常感謝你很多MxyL! (fileInput.getChannel()。size()',那麼它的工作原理:) – WilliamZ

+0

使用'if(fileInput.available() )== 0)'而不是'if(fileInput.getChannel()。size()== 0)'? – WilliamZ

+0

哎呀它是'尺寸()'不''長度'我通常會讓這兩個混合起來。在這種情況下'可用'應該沒問題。我只是不太喜歡描述中的聲音。 – MxyL