# Serialisieren von mehreren Objekten



## balu2000 (28. Dez 2007)

Hallo Zusammen!

Ich habe folgendes Problem:

ich möchte mehrere Objekte serialisieren und in einer Datei speichern, um sie später wieder auslesen zu können.

Jedes Objekt hat als Attribut eine eindeutige ID, anhand welcher ich später wieder auf die einzelnen Objekte zugreifen möchte.

Standardmäßig geht das folgendermaßen:

```
package se;

import se.Student;
import java.io.*;
import java.util.Date;

public class StudentenVerwaltung{

	private static Student student = new Student();
	
	
	public static void studentAnlegen(int matNr, String vor, String nach){

		student.setMatrikelnummer(matNr);
		student.setVorname(vor);
		student.setNachname(nach);
	}

	public static void main(String args[]) throws IOException, ClassNotFoundException{
		
		studentAnlegen(1,"Max","Mustermann");
		studentAnlegen(2,"Hans","Wurst");
		studentAnlegen(3,"Herr","Gesangsverein");
		
		FileOutputStream fos = new FileOutputStream("t.tmp");
		ObjectOutputStream oos = new ObjectOutputStream(fos);

		oos.writeObject(student);

		oos.close();
		
		FileInputStream fis = new FileInputStream("t.tmp");
		ObjectInputStream ois = new ObjectInputStream(fis);

		Student student = (Student) ois.readObject();

		ois.close();
		
		System.out.println(student.nachname);
		
	}

	
	
}
```

Das Problem ist folgendes: jeder Aufruf der Methode "studentAnlegen() überschreibt das zuletzt geschriebene Objekt in der Datei.
Wie kann ich es erreichen, dass alle Objekte persistent werden und über das Attribut "matrikelnummer" wieder aufgerufen werden können?

Danke für die Hilfe!


----------



## SlaterB (28. Dez 2007)

1.
eine statische Variable durch irgendwelche versteckten Hilfsoperationen zu ändern und irgendwo im Programm an richtiger Stelle zu verwenden ist von Grund auf schlecht,

wenn du drei Studenten mit 3 Namen hast, dann erstelle dir doch bitte 3 Studenten-Objekte, und schon sind derartige Probleme undenkbar

2.
> jeder Aufruf der Methode studentAnlegen() überschreibt 
du hast eh nur einen Aufruf (innerhalb eines Programmablaufs), da kann man also nicht wirklich von überschreiben reden,
wenn du 3x speichern willst, dann rufe auch 3x speichern auf (an der richtigen Stelle)


3. 
allerdings ist es korrekt, dass z.B. bei jeder neuen Programm-Ausführung die alte Datei gnadenlos überschrieben wird,
es ist auch durch andere Kommandos nicht trivial möglich, die Datei zu öffnen und einen weiteren Studenten anzufügen,

denkbar wäre höchstens, in eine Datei in einem Rutsch alle drei Studenen zu schreiben
(bisher hst du nur 1x schreiben und auch nur 1x lesen)

4.
> Wie kann ich es erreichen, dass alle Objekte [..] über das Attribut "matrikelnummer" wieder aufgerufen werden können? 

zaubern kann die Serialisierung von alleine nicht, du kannst nur die Objekte in der Reihenfolge, wie sie geschrieben wurden, wieder einlesen,
wenn du danach einen Index nach der Matrikelnummer oder ähnliches aufbauen willst, dann tue dies,
mit Serialisierung hat dies aber direkt nichts zu tun


----------



## Wildcard (28. Dez 2007)

SlaterB hat gesagt.:
			
		

> allerdings ist es korrekt, dass z.B. bei jeder neuen Programm-Ausführung die alte Datei gnadenlos überschrieben wird,
> es ist auch durch andere Kommandos nicht trivial möglich, die Datei zu öffnen und einen weiteren Studenten anzufügen,


Wie meinen?  :shock: 
http://java.sun.com/javase/6/docs/api/java/io/FileOutputStream.html#FileOutputStream(java.io.File,%20boolean)


----------



## SlaterB (28. Dez 2007)

jo, das hatte ich in einem anderen Topic auch mal zuerst geantwortet,
ObjektOutputStream schreibt aber besondere Markierungen
BeginToken, NextObjectToken, EndOfFileToken,
und da gibt es keine Möglichkeit, zwei Dateien zusammenzumergen oder eine alte Datei aufzubrechen

zumindest habe ich auf die Schnelle nix gesehen, 
wenn man bös das letzte Token manuell wegradiert, wirds bestimmt irgendwie gehen  , 
mit append allein ist es jedenfalls nicht getan


----------



## Wildcard (28. Dez 2007)

Das Ding schreibt EOF? :autsch: 
Ein Grund mehr warum Serialisierung kein Ersatz für reguläre Persistierung ist.


----------



## balu2000 (29. Dez 2007)

Sorry für die offensichtlichen Fehler, aber ich bin leider ein Anfänger...

Im Endeffekt soll die Serialisierung die Persistenzschicht übernehmen.
D.h. das Programm soll Studenten aufnehmen und löschen können.

Da neue Objekte nicht an eine bestehende Datei angefügt werden können, wird es ausreichen alle vorhandenen Objekte zum Programmstart auszulesen und beim beenden zu serialisieren und in die Datei zu schreiben.

Allerdings weiss ich immer noch nicht, wie ich mehrere Objekte in eine Datei schreiben kann bzw. aus einer Datei auslesen kann.

Ich kann ja nicht einfach eine statische Anzahl von Objekten erstellen, mit jeweils einer "write"-Methode, da ich nicht im voraus weiß wieviele Daten während einer Session eingepflegt werden...

EDIT:

habe selber eine vorläufige Lösung gefunden, indem ich einen AttributsVektor statt einzelner Attribute speichere und abrufe.


----------



## SlaterB (30. Dez 2007)

du speicherst doch nicht etwa mehrere Namen in einem Studenten?
erstelle dir lieber mehrere Studenten-Objekte mit jeweils einem Namen,

mehrfaches Schreiben und Lesen: mehrfach read/ write aufrufen


----------



## balu2000 (30. Dez 2007)

Ich mache es folgendermaßen:


```
package se;

import se.Student;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;

public class StudentenVerwaltung implements Serializable{

	Vector list = new Vector();
	String fileName;
	
	public StudentenVerwaltung(String file){
		fileName = file;
	}
	
	public void addStudent(Student student){
		list.addElement(student);
	}
	
	public String toString(){
		return list.toString();
	}
	
	public void save() throws IOException{
		OutputStream outFile = new FileOutputStream(fileName);
		ObjectOutputStream outObj = new ObjectOutputStream(outFile);
		outObj.writeObject(this);
		outObj.close();
	}
	
	public static StudentenVerwaltung fromFile(String studentFile) throws OptionalDataException, ClassNotFoundException, IOException{
		InputStream inFile = new FileInputStream(studentFile);
		ObjectInputStream inObj = new ObjectInputStream(inFile);
		
		StudentenVerwaltung recovered = (StudentenVerwaltung) inObj.readObject();
		
		inObj.close();
		return recovered;
	}
	
	
	
	public static void main(String args[]) throws IOException, ClassNotFoundException{
		
		StudentenVerwaltung v = new StudentenVerwaltung("studenten.dat");
		v.addStudent(new Student(1,"Max","Mustermann"));
		v.addStudent(new Student(2,"Hans","Wurst"));
		v.addStudent(new Student(3,"Herr","Gesangsverein"));
		System.out.println(v);
		
		v.save();
		
		StudentenVerwaltung recoveredClass = StudentenVerwaltung.fromFile("studenten.dat");
		System.out.println(recoveredClass);
		System.out.println(recoveredClass.list.get(0));
	}

	
	
}
```

Das funktioniert so weit ganz gut.

Allerdings weiß ich nicht, wie ich nun auf einzelne Attribute (also z.b. der Nachname von dem Studenten mit Index = 1 in dem Vektor) zugreife und nicht immer alle 3 Attribute ausgegeben werden.

Die Klasse "Vector" bietet da scheinbar keine Methode für, würde das mit einer Collection oder etwas ähnlichem gehen?

PS: Danke für die bisherige Hilfe. Das hat mich deutlich weitergebracht 

EDIT: hab meinen Fehler gefunden. In der Klasse "Student" habe ich die Attribute in Strings umgewandelt, das war natürlich Quatsch.


----------

