0

I'm a beginner with Java and I meet a problem with a read/write to text file.

The process :

  • read and display the text file : System.out.println(garage);
  • add a first car : garage.addVoiture(lag1);
  • add a second car : garage.addVoiture(A300B_2);

Here is 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);
}

and here is 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");
  }
}

First execution of main.java, (the text file doesn't exists) I get in console :

  • Aucune voiture sauvegardée !

    • Garage OpenClassrooms *

  • start addVoiture
  • end addVoiture
  • start addVoiture
  • end addVoiture

That's what I want to show in console for first launch.

But second execution of main.java, (the text file exists), I get in console :

  • DEBUG start toString
  • DEBUG end toString

    • Garage OpenClassrooms *

    • Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (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ège chauffant (562.9€), Vitres electrique (212.35€)] d'une valeur totale de 11144.75€
  • DEBUG end addVoiture
  • DEBUG start addVoiture+ Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€
  • DEBUG end addVoiture Only the second car (+ Voiture PIGEOT) is shown in console.

The result I want is both of them, ordered the same way I added them :


  • _ * Garage OpenClassrooms * _ *************************
    • Voiture RENO : Lagouna Moteur ESSENCE 150 Chevaux (10256.0) [GPS (113.5€), Siège chauffant (562.9€), Vitres electrique (212.35€)] d'une valeur totale de 11144.75€
    • Voiture PIGEOT : Lagouna Moteur ELECTRIQUE 1500 W (1234.0) [Climatisation (347.3€), Barre de toit (29.9€), Siège chauffant (562.9€)] d'une valeur totale de 2174.1€

I don't find the solution to this issue, Is it because I don't write correctly both cars : oos.writeObject(voit); or because I don't read it correctly : str += ((Vehicule)ois.readObject()).toString(); ?

I've searched a lot even on stackoverflow but the code seems to be correct. So it may be a problem with the way I write then read the file ?

Thanks a lot if someone can help, I'm spending lots of time but turn around.


Added after @Kevin Anderson informations :


Thanks a lot again for help!

I changed readObject with your script but I still get only the last car added.

I've also seen this post (java.io.StreamCorruptedException: invalid type code: AC) and wasn't able to solve it. So I changed the way I writeObject (stopped appending objects to ObjectOutputStream) and get an almost good result.

Now my ultime issue is with "Type safety: Unchecked cast from Object to List" on readObject().

I think (not sure ?) that it's just an IDE information so I suppose it would be better to do the correct way, so I would like to avoid using (@SuppressWarnings("unchecked")) over (public String toString() {) and do it the best way but I was unable to apply any of all solutions I found on Stackoverflow.

If you have an idea, that would be really perfect !

Here is new 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();
    } 
  }
}

Added solution for Type safety: Unchecked cast from Object to List


Thanks to this post : Type safety: Unchecked cast

The text file contains a List object and when I launch Garage() I needed to add this List object to the existing List voitures.

Eclipse was showing : Type safety: Unchecked cast from Object to List

I could use : @SuppressWarnings("unchecked") to my method, but it looks better to do this way so I don't ignore any warning :

    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
    }       

Hope it helps, sorry for my beginner mistakes ^^, and thanks to all for help !

kobano
  • 419
  • 4
  • 12

2 Answers2

1

The name tells you what you need to do: read an object.

It is not named read File.

In other words: when you use Object streams, your code defines which objects get written in which order. And then, on the other side, similar code has to read these objects in the very same order.

This is all there is to this.

And your current code overwrites the existing file. When you want to "preserve" the file content - then you first have to read in the objects that were stored previously.

GhostCat
  • 127,190
  • 21
  • 146
  • 218
1

Each time you call addVoiture, you're overwriting the data file, not adding onto it. Change your file-opening code to

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

That extra arg true on new FileOutputStream opens an existing file for appending instead of creating a new empty file every time. See the docs here

Also, since you're writing multiple Vehicule objects to your file, you have to execute multiple readObject calls to read all of them back again. The reason you only ever see one car is because you only call readObject one time. You need to keep calling readObject in a loop until you get an 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 ....

With this change, you shouldn't need to catch EOFException with the outer try block anymore because the inner try now handles it.

Kevin Anderson
  • 4,388
  • 2
  • 10
  • 20
  • Thanks to all for overwriting information. But I've added "true" parameter to FileOutputStream for appending, and (str += ((Vehicule)ois.readObject()).toString();) still only returns the last car added (Voiture PIGEOT : Lagouna Moteur ELECTRIQUE). I suppose that it means the file only contains last car added. There is certainly another problem :/ ? – kobano Nov 23 '17 at 19:38
  • Thanks again, I've updated the code but finally changed the way I writeObject and get another information. see updated post. – kobano Nov 25 '17 at 12:34
  • It's ok I found a way to avoid warning during List cast. – kobano Dec 01 '17 at 10:04