序列化 - 为什么readObject不读取整个文件?

时间:2017-11-23 13:29:48

标签: java list casting objectinputstream objectoutputstream

我是Java的初学者,我遇到了对文本文件的读/写问题。

过程:

  • 读取并显示文本文件:System.out.println(garage);
  • 添加第一辆车:garage.addVoiture(lag1);
  • 添加第二辆车:garage.addVoiture(A300B_2);

这是main.java:

import fr.ocr.vehicule2.*;

public class Main {
    public static void main(String[] args) {
     Garage garage = new Garage();
     System.out.println(garage);

     Vehicule lag1 = new Lagouna();
     lag1.setMoteur(new MoteurEssence("150 Chevaux", 10256d));
     lag1.addOption(new GPS());
     lag1.addOption(new SiegeChauffant());
     lag1.addOption(new VitreElectrique());
     garage.addVoiture(lag1);

     Vehicule A300B_2 = new A300B();
     A300B_2.setMoteur(new MoteurElectrique("1500 W", 1234d));
     A300B_2.addOption(new Climatisation());
     A300B_2.addOption(new BarreDeToit());
     A300B_2.addOption(new SiegeChauffant());
     garage.addVoiture(A300B_2);
}

这里是garage.java

package fr.ocr.vehicule2;

import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;


public class Garage {

  private List<Vehicule> voitures = new ArrayList<Vehicule>();;
  ObjectInputStream ois;
  ObjectOutputStream oos;

  public Garage(){
  }

  public String toString() {
    System.out.println("DEBUG start toString");

    String str = "";
    // Vérification de l'existence du fichier de sauvegarde
    if(Files.notExists(Paths.get("garage.txt"))) str += "Aucune voiture sauvegardée !\n";

    str += "*************************\n" 
       + "* Garage OpenClassrooms *\n"
       + "*************************\n";

    // Lecture du fichier texte
    if(Files.exists(Paths.get("garage.txt"))) {
      try {
        ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
          str += ((Vehicule)ois.readObject()).toString();
        ois.close();
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (EOFException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      } 
    }
    System.out.println("DEBUG end toString");
    return str;
  }

  public void addVoiture(Vehicule voit) {

    System.out.println("DEBUG start addVoiture" + voit);

    voitures.add(voit);

    // écriture du fichier texte
    try {
      oos = new ObjectOutputStream(
          new BufferedOutputStream(
            new FileOutputStream(
              new File("garage.txt"))));

//      for(Vehicule V:voitures){
//              oos.writeObject(V);
//          }
      oos.writeObject(voit);
      oos.close();

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } 
    System.out.println("DEBUG end addVoiture");
  }
}

首次执行main.java,(文本文件不存在)我进入控制台:

  • Aucunevoituresauvegardée!
    • Garage OpenClassrooms *
  • 启动addVoiture
  • 结束addVoiture
  • 启动addVoiture
  • 结束addVoiture

这就是我想在首次发布时在控制台中显示的内容。

但是第二次执行main.java,(文本文件存在),我进入控制台:

  • DEBUG start toString
  • DEBUG end toString
    • Garage OpenClassrooms *
    • Voiture PIGEOT:Lagouna Moteur电子1500瓦(1234.0)[Climatisation(347.3€),Barre de toit(29.9€),Siègechauffant(562.9€)] d'une valeur totale de 2174.1€
  • DEBUG start addVoiture + Voiture RENO:Lagouna Moteur ESSENCE 150 Chevaux(10256.0)[GPS(113.5€),Siègechauffant(562.9€),Vitres electrique(212.35€)] d'une valeur totale de 11144.75€
  • DEBUG end addVoiture
  • DEBUG start addVoiture + Voiture PIGEOT:Lagouna Moteur电子1500瓦(1234.0)[Climatisation(347.3€),Barre de toit(29.9€),Siègechauffant(562.9€)] d'une valeur totale de 2174.1€
  • DEBUG结束addVoiture 控制台中仅显示第二辆车(+ Voiture PIGEOT)。

我想要的结果是他们两个,按照我添加它们的方式排序:

  • _ *车库OpenClassrooms * _ *************************
    • Voiture RENO:Lagouna Moteur ESSENCE 150 Chevaux(10256.0)[GPS(113.5€),Siègechauffant(562.9€),Vitres electrique(212.35€)] d'une valeur totale de 11144.75€
    • Voiture PIGEOT:Lagouna Moteur电子1500瓦(1234.0)[Climatisation(347.3€),Barre de toit(29.9€),Siègechauffant(562.9€)] d'une valeur totale de 2174.1€

我找不到解决这个问题的方法, 是因为我没有正确地写两辆车:oos.writeObject(voit); 或者因为我没有正确读取它:str + =((Vehicule)ois.readObject())。toString(); ?

我甚至在stackoverflow上搜索了很多,但代码似乎是正确的。所以这可能是我写的方式然后读取文件的问题?

如果有人能提供帮助,我会非常感谢,我会花很多时间转身。

在@Kevin Anderson信息之后添加:

再次感谢您的帮助!

我用你的脚本更改了readObject,但我仍然只添加了最后一辆车。

我也看过这篇文章(java.io.StreamCorruptedException: invalid type code: AC)但无法解决。所以我改变了writeObject的方式(停止将对象附加到ObjectOutputStream)并获得了几乎好的结果。

现在我的ultime问题是在readObject()上使用“类型安全:从对象到列表的未经检查的强制转换”。

我认为(不确定?)它只是一个IDE信息所以我认为最好采用正确的方式,所以我想避免使用(@SuppressWarnings(“unchecked”))(public String toString) (){)并以最好的方式做到但我无法应用我在Stackoverflow上找到的任何解决方案。

如果你有一个想法,那将是非常完美的!

这是新的garage.java:

public class Garage {

  private List<Vehicule> voitures = new ArrayList<Vehicule>();
  private ObjectInputStream ois;
  protected static ObjectOutputStream oos;

  public Garage(){}

  public String toString() {

    String str = "";

    // Vérification de l'existence du fichier de sauvegarde
    if(Files.notExists(Paths.get("garage.txt"))) {
      str += "Aucune voiture sauvegardée !\n";
    }

    str += "*************************\n" 
       + "* Garage OpenClassrooms *\n"
       + "*************************\n";

    // Lecture du fichier texte
    if(Files.exists(Paths.get("garage.txt"))) {
      try {
        ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));

        // garage loading during instanciation :
              // Information Eclipse : 
              // Type safety: Unchecked cast from Object to List<Vehicule>
              this.voitures = (List<Vehicule>)ois.readObject();

        // Affichage des voitures enregistrées dans le fichier texte
        for(Vehicule V : this.voitures){
          str += V;
        }


              // To avoid "Type safety: Unchecked cast from Object to List<Vehicule>" :
        // those 2 solutions show identical information "Type safety: Unchecked cast from Object to List<Vehicule>"

        // First tried solution :
        // this.voitures = new new ArrayList<Vehicule>((List<Vehicule>)ois.readObject()); 

              // Second tried solution :
//              if(ois.readObject() instanceof List<?>){
//                  List<?> list = (ArrayList<?>)ois.readObject();
//                  for(Object e : list){
//                     if(e instanceof Vehicule){
//                       this.voitures = (List<Vehicule>)e;
//                     }
//                  }
//              }


        ois.close();
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (EOFException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      } 
    }
    return str;
  }

  public void addVoiture(Vehicule voit) {

    voitures.add(voit);

    // écriture du fichier texte
    try {
      oos = new ObjectOutputStream(
          new BufferedOutputStream(
            new FileOutputStream(
              new File("garage.txt"))));

      // Enregistrement detoutes les voitures dans le fichier texte
      oos.writeObject(voitures);

      oos.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } 
  }
}

为类型安全添加了解决方案:取消选中从对象到列表的强制转换

感谢此帖:Type safety: Unchecked cast

文本文件包含List对象      当我启动Garage()时,我需要将此List对象添加到现有的List voitures。

Eclipse显示:     类型安全:从对象到列表的未选中转换

我可以使用:@SuppressWarnings(“unchecked”)到我的方法,但这样做看起来更好,所以我不会忽略任何警告:

    List<?> list = (List<?>) ois.readObject();
    for(int i = 0; i < list.size(); i++) {
      this.voitures.add((Vehicule) list.get(i)); // instanciation
      str += (Vehicule) list.get(i);// Added to console message
    }       

希望它有所帮助,对不起我的初学者错误^^,并感谢所有人的帮助!

2 个答案:

答案 0 :(得分:1)

该名称告诉您需要做什么:阅读 对象

它未命名为 read 文件

换句话说:当您使用对象流时,您的代码会定义哪些对象以哪种顺序写入。然后,另一方面,类似的代码必须以相同的顺序读取这些对象。

这就是全部。

您当前的代码会覆盖现有文件。当你想要&#34;保存&#34;文件内容 - 然后您首先必须读入先前存储的对象。

答案 1 :(得分:1)

每次调用addVoiture时,您都会覆盖数据文件,而不是添加到数据文件中。将文件打开代码更改为

oos = new ObjectOutputStream(
      new BufferedOutputStream(
        new FileOutputStream(
          new File("garage.txt"), true)));

true上的额外arg new FileOutputStream会打开现有文件以进行追加,而不是每次都创建新的空文件。请参阅文档here

此外,由于您正在向文件中写入多个Vehicule个对象,因此必须执行多个readObject调用才能再次读取所有这些对象。您只看到一辆车的原因是因为您只拨打readObject一次。您需要继续调用readObject,直到获得EOFException

try {
        ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File("garage.txt"))));
        for(;;){
            try {
               str += ((Vehicule)ois.readObject()).toString();
            } catch (EOFException eofe) {
               break;
            }
        }
        ois.close();
      }
} catch ....

通过此更改,您不再需要使用外部EOFException块捕获try,因为内部try现在可以处理它。