Avatar billede trp79 Nybegynder
10. februar 2003 - 13:32 Der er 30 kommentarer og
1 løsning

Serializing:How to med ArrayList,som består af en række objekter?

Hejsa,
Jeg er helt newbie hvad angår serializing. Jeg troede jeg kunne bruge en metode i understående stil.
Jeg har implementeret serielizable i de classer som jeg skal have ned på fil.
Håber noget kan tilrette min metode eller give mig et andet eksempel som jeg kan arbejde ud fra. Hvad betyder flush i øvrigt når man arbejder med en Stream? at man smider den væk(samler garbage collector ikke selv den op?)?

        public void objectToFile(Serializable structure, String filename)
        {
            try{
                ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(filename));
                out.writeObject(structure);
                out.flush();
                out.close();
                }
            catch(IOException e)
                {System.out.println("IO problem "+e.getMessage());}
        }
Avatar billede jakoba Nybegynder
10. februar 2003 - 13:58 #1
streams har næsten altid en buffer, der samler bogstaver op til den har fx 100 bogstaver, når bufferen har nok skriver den dem allesammen til den fil eller device den stem er sat op for.
På den måde sparer den en masse tid fordi altmulig baggrunds-admin (er diske klan, har jeg retten til denne device, ...) kun behøver at ske een gang for hver 100 bytes istedet for for hver eneste byte.

Men det medfører så også at når der ikke er mere at sende til en stream, så vil der sikkert stadig ligge noget i bufferen der ikke er sendt. metoden flush kan så bruges til at sige "Det skal sendes nu, selvomogså bufferen ikke er 'fuld nok'."

Faktisk tror jeg flush er unædvendig her. Jeg tror (men er ikke 100% sikker på) at dit kald til close lige bagefter automatisk vil flushe bufferen hvis der er noget i den der ikke er sendt.

med din metode objectToFile genåbner du din fil for hvert objekt der skal sendes. det går ikke godt da nr 2 objekt sp over skriver det første, osv osv. Din outputstream bør ligge udenfor metoden og blive åbnet separat.

mvh JakobA
Avatar billede trp79 Nybegynder
10. februar 2003 - 14:32 #2
Jeg har nu flyttet output streamen uden for metode, men får denne fejl:
symbol  : method objectToTile (java.util.List,java.io.ObjectOutputStream)
location: class run
        objectToTile(fliste,out);
                ^
1 error

Tool completed with exit code 1

Jeg har plukket lidt ud af koden:

List fliste = new ArrayList();

fliste.add(a);  //det er objekter der tilføjes til fliste
fliste.add(b);
fliste.add(c);
fliste.add(d);

ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("test"));
objectToTile(fliste,out);

public void objectToFile(Serializable structure, ObjectOutputStream out)
{
try{
        out.writeObject(structure);
    out.close();
  }
catch(IOException e)
    {
          System.out.println("IO problem "+e.getMessage());}
    }

Hvad gør jeg forkert? og hvordan retter jeg det?
Avatar billede jakoba Nybegynder
10. februar 2003 - 14:52 #3
det ved jeg ikke for du viser kun en brøkdel af din kode.

Vil metoden add i fliste gemme a i serialized form inden i din fliste eller gemmer fliste blot en reference til det objekt add får som parameter?

Kan det passe at du definere metoden objectToFile inde midt i en anden metode ?

dit kald til close() på den der stream skal også kun ske een gang, efter du har skrevet alt hvad du ville.
Avatar billede jakoba Nybegynder
10. februar 2003 - 15:03 #4
Avatar billede trp79 Nybegynder
10. februar 2003 - 15:07 #5
Jeg får samme fejl selvom jeg nu har flyttet close() til efter metode kaldet.
objectToFile er selvf. en selvstændig metode.


public static void main(String[] arguments)
{
    List fliste = new ArrayList();
    List filmliste = new ArrayList();
    List temp = new ArrayList();

    Biograf Palads = new Biograf("Palads");
    Biograf Kinop = new Biograf("Kinopalæet");

    Sal K1 = new Sal (1, Kinop, 100);
    Sal K2 = new Sal (2, Kinop, 200);
    Sal K3 = new Sal (3, Kinop, 300);
    Sal K4 = new Sal (4, Kinop, 400);
    Sal P1 = new Sal (4, Palads, 100);
    Sal P2 = new Sal (4, Palads, 200);
    Sal P3 = new Sal (4, Palads, 300);
    Sal P4 = new Sal (4, Palads, 400);   
        Film F1 = new Film ("The Rock","Action");
    Film F2 = new Film ("Ridskolen","Porno");
    Film F3 = new Film ("Gladiator","Action");
    Film F4 = new Film ("Polle", "Komedie");

    filmliste.add(new Film ("The Rock","Action"));
    filmliste.add(new Film ("Ridskolen","Porno"));
    filmliste.add(new Film ("Gladiator","Action"));
    filmliste.add(new Film ("Polle", "Komedie"));

    Forestilling a = new Forestilling (F4, P3,"28-Feb-2003 12:00");
    Forestilling b = new Forestilling (F4, K3,"28-Feb-2003 14:30");
    Forestilling c = new Forestilling (F4, K3,"02-Mar-2003 17:00");
    Forestilling d = new Forestilling (F3, P4,"03-Feb-2003 14:00");

    fliste.add(a);
    fliste.add(b);
    fliste.add(c);
    fliste.add(d);
    ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("test"));
    objectToTile(fliste,out);
        out.close();
}

add tilføjer bare et objekt til fliste på normal vis. Et uddrag at Forestillingen klassen:

public class Forestilling implements Serializable
{
  public Sal sal;
  public Film film;
  public int counter=0;
  public Date d;
  private DateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm");

  public Forestilling(Film filmV, Sal salV, String date)
  {
      film=filmV;
      sal=salV;
      try {d = df.parse(date);} catch (ParseException e) {}
  }
Avatar billede trp79 Nybegynder
10. februar 2003 - 15:22 #6
flyttet close() til efter metode kaldet "objectToTile(fliste,out);"
Jeg kigger lige lidt på sun site. Tak for hjælpe indtil videre....
Avatar billede arne_v Ekspert
10. februar 2003 - 16:11 #7
Du kan sagtens serialisere en ArrayList hvis alle de objekter
du har gemt i ArrayList er serializable.

En flush sikrer bare at dit skrevne objekt ikke ligger
og gemmer sig i en buffer men faktisk bliver skrevet.

Med hensyn til din kode tro rjeg du skal droppe den metode,
altså:

    ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("test.dat"));
    out.writeObject(fliste);

meget simplere !
Avatar billede trp79 Nybegynder
10. februar 2003 - 16:55 #8
Det var da noget nemmere :o)
Men hvis jeg nu vil lave det som en metode og kalde metoden fra min main metode, så får jeg jo lidt bøvl med static contra non-static. Hvordan kan jeg slippe uden om det? Man kan åbenbart ikke lave en " static ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("test.dat"));"
Avatar billede arne_v Ekspert
10. februar 2003 - 17:04 #9
Du burde godt kunne lave:

public class X {
  private static ObjectOutputStream out;
  private static void dowrite() {
      out.writeObject(something);
  }
  public static void main(String[] args) {
      out = new ObjectOutputStream( new FileOutputStream("test.dat"));
      ...
      dowrite();
  }
}

Men jeg synes, at det er meget dårligt design.

Jeg vil anbefale noget i retning af:

public class X {
  private static ObjectOutputStream out;
  private void dowrite(ObjectOutputStream out) {
      out.writeObject(something);
  }
  public static void main(String[] args) {
      out = new ObjectOutputStream( new FileOutputStream("test.dat"));
      X x = new X();
      ...
      x.dowrite(out);
  }
}

hvis du kan følge mig.
Avatar billede arne_v Ekspert
10. februar 2003 - 17:13 #10
Eller endnu bedre:

public class X {
  private void dowrite(ObjectOutputStream out) {
      out.writeObject(something);
  }
  public static void main(String[] args) {
      ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("test.dat"));
      X x = new X();
      ...
      x.dowrite(out);
  }
}

formålet er at gøre klassen X uafhængig af main.
Avatar billede arne_v Ekspert
10. februar 2003 - 17:19 #11
Eller i den mere sofistikerede udgave:

public class X {
  private OutputObjectStream out = null;
  public void setOutput(ObjectOutputStream out) {
      this.out = out;
  }
  public void dowrite() {
      out.writeObject(something);
  }
  public static void main(String[] args) {
      ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("test.dat"));
      X x = new X();
      ...
      x.setOutput(out);
      x.dowrite();
  }
}

Jeg håber ikke at jeg forvirrer dig med den mange eksempler.

Jeg vil bare gerne vise nogle af de mange muligheder der er.
Avatar billede trp79 Nybegynder
10. februar 2003 - 17:20 #12
Forrygende, det kan jeg i hvert fald bruge :)

En måde at læse dataene over i listen på igen er så:
        try{
            //read the object back in
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("yesyes.dat"));
            fliste.add(in.readObject());
            in.close();
                }
        catch(IOException ee)
            {System.out.println("IO problem "+ee.getMessage());}
            catch (ClassNotFoundException ee)
            {System.out.println("Class problem(ikke fundet "+ee.getMessage());}

Men hvor meget information gennem den i yesyes.dat,
Hvis nu de forskellige objekter der ligger i fliste består af andre objekter, så er gemmer den vel også dem?

Det er vel det smarte ved strukturen?
Avatar billede arne_v Ekspert
10. februar 2003 - 17:34 #13
Den gemmer alt d.v.s. alle members ("felter") i klassen - undtagen
dem du eksplicit beder den lade være med at gemme ved at give
attributten transient.

Også objekter der er gemt i objekter.

Hvis et objekt ikke kan gemmes fordi det ikke er serializable så får
du en exception på gemme tidspunkt.

Så du skulle have det hele.

Det største problem du skal være opmærksom på er, hvis
du skriver et objekt med en version af klassen og så forsøger
at læse det med en nyere version af klassen. Det virker ikke
godt !
Avatar billede trp79 Nybegynder
10. februar 2003 - 18:08 #14
Tak for hjælpen, det virker efter hensigten nu.

Mvh
Torben :o)
Avatar billede trp79 Nybegynder
10. februar 2003 - 23:23 #15
Der var jeg vist lidt for hurtig :o(
Jeg har dog ingen problemer med:

ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("film.dat"));
out.writeObject(fliste);

Men når jeg så vil læse det ind med:
    try{
            //read the object back in
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("film.dat"));
            fTliste.add(in.readObject());
            in.close();
                }
        catch(IOException ee)
            {System.out.println("IO problem "+ee.getMessage());}
            catch (ClassNotFoundException ee)
            {System.out.println("Class problem(ikke fundet "+ee.getMessage());}

og printe det ud med:
        Film current = null;
              for( int i = 0; i < fTliste.size(); i++ ) {
                current = (Film)fTliste.get(i);
                System.out.println("titel: " +current.getTitle());
                System.out.println("genre: " +current.getGenre());
              }

Får jeg en fejl når jeg kører det, ikke når jeg compilere det. Fejlen er:
Exception i thread "main" java.lang.ClassCastException
at run.main(run.java:131)

lidt mer kode...
        Film current = null;
              for( int i = 0; i < fTliste.size(); i++ ) {
Linie 131 -->            current = (Film)fTliste.get(i);
                System.out.println("titel: " +current.getTitle());
            System.out.println("genre: " +current.getGenre());
              }

Har du en ide om hvad det kan være? smider gerne lidt flere point hvis det er...
mvh
Torben
Avatar billede trp79 Nybegynder
10. februar 2003 - 23:28 #16
min film klasse:

import java.io.*;
import java.util.*;

public class Film implements Serializable
{
  public String title;
  public String genre;

  public Film(    String titleV, String genreV)
  {
    title=titleV;
    genre=genreV;
  }
      public String getTitle()        {return title; }
      public String getGenre()        {return genre; }
}
Avatar billede arne_v Ekspert
11. februar 2003 - 10:17 #17
Så vidt jeg kan se så gemmer du listen:

out.writeObject(fliste);

men forsøger at læse den ind som enkelt film:

fTliste.add(in.readObject());
...
current = (Film)fTliste.get(i);

Prøv med:

fTliste = (ArrayList)in.readObject();
...
current = (Film)fTliste.get(i);
Avatar billede trp79 Nybegynder
11. februar 2003 - 12:28 #18
Det virkede i hvert fald :o) Men nu er jeg selvfølgelig røget i et nyt problem. Jeg får en fejl ved understående skrivning:

Saede saedeP4[] = new Saede[P4.pladser];
for(int i=1; i<=P4.pladser; i++)
{
  String tal = String.valueOf(i);
  saedeP4[i-1]=new Saede(P4,i);
}
saedeliste.add(saedeK1);

ObjectOutputStream outSaede = new ObjectOutputStream( new FileOutputStream("Saede.dat"));
outSaede.writeObject(saedeliste);

Hvad kan det skyldes og hvordan kan jeg slippe uden om det?

Skulle jeg ikke lige oprette et nyt spørgsmål med nogle point til dig Arne og henvise det dette spg?
Avatar billede arne_v Ekspert
11. februar 2003 - 12:32 #19
Hvilken fejl får du ?

Er Saede eventuelt ikke serializable ?
Avatar billede arne_v Ekspert
11. februar 2003 - 12:33 #20
Du må da meget gerne give mig lidt ekstra point !
Avatar billede trp79 Nybegynder
11. februar 2003 - 12:36 #21
Fejlen bliver catch'et her:
  catch(IOException ee)
  {System.out.println("IO problem ved skrivning "+ee.getMessage());}

På skærmen lyder fejlen så "IO prblem ved skrivning Saede"
Altså fejl ved skrivning til Saede.dat :(

Opretter fluks et spg med 60 points til dig.
Avatar billede trp79 Nybegynder
11. februar 2003 - 12:37 #22
Avatar billede arne_v Ekspert
11. februar 2003 - 12:42 #23
Står der ikke mere end "IO prblem ved skrivning Saede" - altså
indeholder ee.getMessage() ikke noget ?
Avatar billede trp79 Nybegynder
11. februar 2003 - 12:47 #24
den må så netop indeholde "saede", da:
{System.out.println("IO problem ved skrivning "+ee.getMessage());}
ikke benævner "saede".
Avatar billede arne_v Ekspert
11. februar 2003 - 12:55 #25
Din kode ser umiddelbart OK ud, men den må da skrive
lidt om hvad det er for en IOException.

Kan du evt. lave det om til:

catch(IOException ee) {
    System.out.println("IO problem ved skrivning "+ee.getMessage());
    ee.printStackTrace();
}

og poste hele fejl-meddelelsen ?
Avatar billede trp79 Nybegynder
11. februar 2003 - 13:02 #26
Det er lidt af en smøre, men her kommer den:
IO problem ved skrivning af Saede
java.io.NotSerializableException: Saede .....  ARHHHH jeg tæver mig selv!

måske det vil hjælpe en smule med "implements Serializable". Men nu fandt vi da frem til fejlen, skønt :o)
Avatar billede arne_v Ekspert
11. februar 2003 - 13:08 #27
Det afgørende er jo ikke vejen til at få det til at virke, men
at få det til at virke.

Iøvrigt er jeg selv ret glad for ee.printStackTrace fordi den
udover fejlen også fortæller hvor fejlen er sket.

Men indrømmet den kan godt give lidt meget output - et vindue
hvor man kan scrolle tilbage er en god ting.
Avatar billede trp79 Nybegynder
11. februar 2003 - 13:34 #28
Ja, men det kan nu godt være lidt irreterende med "åndsvage fejl"... Måske man skulle begynde at gøre mere brug af printStackTrace, den viser jo ret åbenlyst fejlen :o)

Nå lige en sidste ting, hvis det er iorden..
som det er nu tilføjer jeg arrays af objekter til min arraylist saedeliste:

Saede saedeP4[] = new Saede[P4.pladser];
for(int i=1; i<=P4.pladser; i++)
{
  String tal = String.valueOf(i);
  saedeP4[i-1]=new Saede(P4,i);
}
saedeliste.add(saedeK1);

Men hvordan kommer jeg så ind til objektet igen?

Saede b=null;
b=(Saede)saedeliste.get(0); //virker ikke :o(

Altså hvis jeg nu fx gerne vil tilgå saedeK1[i] i saedelisten, hvordan gør jeg så det? saedeK1[i] er det første objekt i listen.
Avatar billede trp79 Nybegynder
11. februar 2003 - 13:35 #29
saedeK1 skulle selvf. have været saedeP4.
Avatar billede arne_v Ekspert
11. februar 2003 - 13:39 #30
b=((Saede[])saedeliste.get(0))[i];

vil jeg tro.

Altså du henter dit array ud af listen med arrayets position i listen
og elemented ud af arrayet med array index.
Avatar billede trp79 Nybegynder
11. februar 2003 - 15:27 #31
Det fungerer perfekt. Programmet virker nu efter hensigten. Jeg takker endnu engang for hjælpen :o)
Mvh
Torben
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester