2d-array in Datei speichern und lesen

hallo,

ich hab’ ähnliche Schwierigkeiten mit java, wie daniel in seinem Jframe-Problem unten. (Alles heißt immer ganz anders, als man es erwarten würde oder man kann von alleine oder mit Tutorials durchsuchen nicht drauf kommen oder es schlecht oder gar nicht finden, wenn man learning by doing versucht)

Ich will einen 2d-array, der (x,y)-Koordinaten als Grid[x][y] enthält (und iteriert grafisch ausgegeben wird) einfach abspeichern und jederzeit wieder auslesen.

Nun scheint es da vielerlei Möglichkeiten zu geben …
… per FileReader~ bzw ~Writer und read~write(char[]) …
… per DataIn~OutputStream mit read~writeInt() …
… FileIn~OutputStream …
… ByteArrayIn~OutputStream …
mit jeweils einigen anscheinend in Frage kommenden Methoden… nur keine, die 2-dimensionale arrays lies~schreibt *heul* (hehe)
Soll ich dann mit read~ bzw write(byte[]) arbeiten und zwei 1D-arrays irgendswie wieder zusammenflicken (In zwei Dateien, gar??) ? Oder einem read~write() und das Gelesen~Geschriebene zu bzw aus meinem array verarbeiten? read~write(?what?) ? Oder KoordinatenPaare Zeilenweise speichern und auslesen ?
Viel ‚rum-Buffern oder -Pipen brauch‘ ich ja eigentlich nich’.

Oder gibt’s noch 'ne ganz einfache, ganz andere, elegante Lösung ?

Durch Euren Tipp, was geeignet oder am besten wär’ erspart Ihr mir viel 'rumgesuche und ~probiererei ;o]

Danke

PS: snapshots machen hab’ ich allein hingekriegt, da war die Suche nach BufferedImage, RenderableImage usw im javax.imageio zielführender, und im sun-API und Tut gut beschrieben … hier ist es irgendwie verzweigter und unübersichtlicher

genauer: …
… mein Problem und Frage is’ einfach …
ich versuch’ 'mal zu zeigen, was ich mein:

 _//(Schreib-Output-(Stream?)-Klasse/Interface-Gedöns??)_ 
OutputKlasse outpkl= new_OutputKlasse()_;
 for (x=1; xline-separator?);
 } // für Aus-Pixel Grid[x][y]==0 kein ''else'' vonnöten.
 } }

Nun weiß ich nich’, was die verschiedenen verfügbaren Methoden write(byte[]) write(char[]) write(int c) write() genau in die Datei schreiben… einen array mit geschweiften Klammern und oder Kommata im data={{1,2}{3,4}} -Stil oder kleben die alles ungetrennt aneinander oder mit Leerstellen dazwischen, zB so daß aus (1,2),(17,18),(25,37) …
1217182537
wird, anstatt
1 2, 17 18, 25 37
oder
[1,2][17,18][25,37]
oder
{ {1,2}{17,18}{25,37} }
oder sowas …
… und wie und womit ich die Pärchen am einfachsten wieder auslese?

Ich weiß nich’, was genau die vielen in Frage kommenden Methoden in die Datei schreiben … ob ich einen line-separator brauche, ob all meine Koordinaten-Pärchen aneinander-‚geklebt‘ werden und ich sie dann nich’ mehr richtig auslesen lassen kann … und welcher Daten-Typ (int, char, char[], byte[]) richtig wär’?

Es dürfte ziemlich trivial sein , eigentlich - ich will ja nix sortieren oder Zeilen anspringen oder sowas - nur pärchenweise schreiben und später wieder einlesen

Nun gibt’s java.io.Reader, java.io.Writer - was wohl für chars gedacht is’;
und java.io.In~ bzw ~OutputStream - was wohl für bytes gedacht is’.
Aber im java.io.FileWriter hat write(int c) (von java.io.OutputStreamWriter geerbt) … und soviel in Frage kommende Unterklassen mit ähnlichen Methoden

versteht Ihr?

Moien

… und wie und womit ich die Pärchen am einfachsten wieder
auslese?

Es gibt 3 Wege:

  • ObjectStreams: recht langsam und drehen durch wenn die gespeicherte Klasse sich zwischendrin ändert. OK, das sollte bei int, long, short & Co nicht so oft vorkommen.

  • IrgendwasWriter/Reader: (genauer BufferedReader(Writer)) Die Daten als ASCII-Text speichern so dass man mit jedem Texteditor dran kommt. Dann braucht man zwischen jedem Array ein Zeichen und zwischen jedem Element ein anderes. Das Feld:

    1 2 3
    4 5 6
    7 8 9

wird dabei zu: 1,2,3 4,5,6 7,8,9

zerlegt wird das ganze wieder mit StringTokenizer. Die einzelnen Werte werden mit Integer.parseInt(…) gewandelt.

  • IrgendwasInput/Output: (genauer DataIn(Out)putStream) die Werte binär speichern. D.h. keine Wandelung in ASCII, kein zurückparsen. Alles über writeInt()/readInt(). Dabei kann man sich das Zerlegen sparen.

Dann sollte man vor jedes Array seine Länge speichern dabei das zurückwandeln einfacher geht. Als im Beispiel von vorhin:

3 3,1,2,3 3,4,5,6 3,7,8,9

Man liest die erste 3 und weiss das 3 subarrays kommen werden. Man liest die nächste 3 und weiss dass das subarray 3 Elemente hat. usw…

welcher Daten-Typ (int, char,
char[], byte[]) richtig wär’?

Der gleiche Typ wie das Array hat.

cu

1 Like

Nimm einfach mal ein Blatt Papier und schreib die Daten da drauf. Genau so kannst du dann deine Werte auch in eine Datei schreiben um Zeilenumbrüche, Leerzeichen etc. musst du dich dabei aber schon selbst kümmern :wink:

Hallo,

im Gegensatz zu Pumpkin würde ich auf http://java.sun.com/javase/6/docs/api/java/io/DataIn… und http://java.sun.com/javase/6/docs/api/java/io/DataOu… setzen.

Beispiel kannst Du googeln „DataInputStream example“ oder unter http://books.google.com/books?id=7bGL7LFTwoIC&pg=RA1… nachschauen.

Zum Speichern des Arrays mußt Du dir für Dein Array ein Speicherformat ausdenken. Das ist aber eigentlich ganz einfach. Ich geh mal davon aus, dass das Array m Zeilen und n Spalten hat. Somit hast Du insgesamt m*n Elemente. Diese beiden Zahlen kannst Du am Anfang einfach als Longs speichern. Danach kommen entsprechend viele Booleans. Und hier immer schön true und false abspeichern.

Um die Dateigröße würde ich mir erst mal keine Gedanken machen. Erst mal den Algortihmus zum Laufen bekommen; nachher kannst Du immer noch http://java.sun.com/javase/6/docs/api/java/util/zip/… und http://java.sun.com/javase/6/docs/api/java/util/zip/… experimentieren).

Hoffe das es Dir helfen wird,
Frank

ihr habt alle meine Frage nich’ kapiert
ersma’ Danke für Eure Antworten, aber …

mein Problem is’, welche von all den Klassen inoutputstreamfilewriterreader (sowie willkürlich daraus gemischte Klassen, die auch alle existieren in java)
mit noch mehr unübersichtlichen Klassen für pipen, buffern, serialisieren usw,
dann die vielen Methoden, von denen ich glaub’ nur die einfachste brauch’, wo ich doch nur Pärchen von int speichern und wieder auslesen will
Sowie den je nach Methode nötigen passenden Datentyp für mein Grid[x][y] in diesem Gewimmel zu finden. Bestimmt genügt eine Methode, die int lesen und schreiben kann, nur pärchenweise halt … Ich will deswegen keine zwei oder drei arrays serialisieren, nichma’ einen, sondern …
ich will nur nich’, daß
aus 1,2 3,4 17,18
12341718 wird
Der Tipp mit Leerstellen zwischen den Partnern und Zeilen zwischen den Pärchen (aus Partnern) war schon ganz gut.
aber welche Klasse, welche zugehörige Methode schafft das am einfachsten
Und wie schreib ich Leerstellen und Zeilenumbrüche in meine Datei - „/n“ für Zeilenumbruch = String, wo es doch um int-Pärchen geht.
Muß ich da filewriter.write(1);
filewriter.write("");
filewriter.write(2);
filewriter.write("/n");
usw
machen, um
//Datei
1 2
usw
//eof
zu kriegen?
Also write(String string) oder
writeString() oder
write(int n) oder
write()
oderoderoder

versteht Ihr nich’?
Könnt Ihr mir nich’ einfach die passende Klasse und Methode(n) sagen, daß mein Beispiel im posting ‚‚genauer‘‘ funktioniert, bitte!?

mein Problem is’ nich, irgendwelche long - mit long hab’ ich da gar nix zu tun.
Auch hab’ ich nix zu serialisieren, glaub’ ich.
Und, ob ich nun Elemente der Pärchen mit Leerzeichen oder Kommas oder alles noch in geschweiften Klammern trenn’, is’ mir ziemlich egal, … Hauptsache, ich krieg’s wieder trivial ausgelesen. Aber mit welcher Klasse (zum Schreiben und Lesen) und welcher Methode?

Glaub’ aber, daß die Vorschläge von pumpkin auf mein Problem schon ziemlich genau zutreffen … muß es mal ausprobieren, noch!

Viel Danke, einstweilen!

o)

Hallo!

Ich weiß zwar nicht, wozu dieses Hinundherkonvertiere von int nach Zeichenkette und beim Einlesen wieder zurück gut sein soll, aber was solls.

Das sei die Datei:

435 43
435 234
234 23
234 435

Zum zeilenweise Einlesen benutzt Du BufferedReader#readLine(), zum Aufsplitten am Leerzeichen nimmst Du String#split() und für das Konvertieren in Integerwerte nimmst Du Integer.parseInt().

Zum zeilenweise Speichern der int-Paare packst Du 2 ints von einem Leerzeichen getrennt in einen String und schreibst diesen String mit BufferedWriter#write() in die Datei und dazu immer noch ein BufferedWrite#newLine() für den Zeilenumbruch.

Zum Drumherum um BufferedReader und BufferedWriter findet sich sicherlich was in Deinem Javabuch.

Major

Hallo!

Wenn du einfach nur ein Integer nach dem anderen schreiben willst, dann würde ich das über die Klasse RandomAccessFile machen. Dort gibt es eine Funktion, die heißt writeInt. Sie schreibt genau die vier Byte des jeweilige Integers in die Datei. Über readInt() kannst du die Werte dann ganz einfach wieder auslesen. Da es sich immer um genau vier Byte handelt bracuhst du weder Trennzeichen noch sonst irgendwas. Auch Zeilenumbrüche werden nicht benötigt. Du kannst die Daten dann in einem Editor natürlich nicht im Klartext sehen, aber ich glaube das ist auch nicht gewollt.

outpkl= new RandomAccessFile(dateiname, modus);
for (x=1; x Wird nicht benötigt
}
}
}
outpkl.close()

mfg

lucas_d

1 Like

falsch ausgedrückt?
Mannomann, was 'ne schwere Geburt …
Ich versuch’s nochmal anders bzw ganz von vorne zu erklären:

Ich hab einen Zellautomaten, der die An- und AUS-Pixel als zB
Grid[17][18]=1;
oder (uninterressant):
Grid[12][18]=0;
hat.
Die Koordinatenebene habe also ich den array-Elementen per Wert zugeordnet:
AN=1 (schwarzes Pixel), AUS=0 (leeres Null-Pixel).
Der int Grid[][]=new int(300][300] ist zweidimensional auf einer 300x300 Malfläche.
Nun will ich alle AN-Pixel (also alle Grid(x][y]==1) einer Situation aus AN-Pixeln speichern in einer Datei, damit ich sie auch nach Programm-Ende oder PC-neustart als Schablone aus AN-Pixeln laden (bzw Lesen) kann.

Ich brauch’ also nur, wenn zB
Grid[17][18]==1
ist - in einer for-for-Schleife für x und y - immer, wenn
Grid[x][y]==1
ist, x auslesen und y auslesen und in meine Datei schreiben.
zB als (NUR AN-Pixel)
(if (Grid[x][y]==1) { filewriter(oderwasauchimmer).write(x); write(y}; }
so daß zB
1 2
17 18
12 35
'in die Datei geschrieben wird.

Mein Problem ist nur, daß ich nicht weiß, welche Klasse (OutPutStream? FileWriter? DataOutPutStream? usw … von Buffered- und Piped-Kram ‚mal ganz zu schweigen)
… mit welcher Methode ( write(int) write(String) write(byte[]) write[char]) write() writeString() writeInt() undundund??? )
… ich das am trivialsten mach‘.
… so, daß es ebenso trivial wieder ausglesen werden kann als
Grid[read(x)][Grid[read(y)]

versteht Ihr jetzt?
Es is’ wirklich trivial, nur ich blick’ durch dieses ganze Write®-Read(er)-In-Output-Stream(oder nich’Stream)-Gedöns-mit-jeweils-verfügbaren-Methoden-Gedöns nich’ durch.
(Will mir nur ersparen, alle Writers, Readers, Outputs, Streams, mit deren Unterklassen und all deren Methoden (=ca. 17.000 Kombinationen) auszuprobieren und mit einem Editor nachzugucken, was für Zeichen nun in meine Datei geschrieben wurden, bis brute-force irgendwann ‚ne praktikable Lösung dabei is‘)

Danke nochma’
RoNeunzig

RandomAccessFile für zeilenweise
sry … hab’ nich’ fertig gelesen, weil:
RandomAccessFile is’ gedacht für zeilenweisen Zugriff auf Dateien …
Das brauch’ ich überhaupt nich’ … ich muß nich’ mitten in meiner Datei Zeilen löschen, ergänzen oder sowas.
thk

Halt … Moment … das klingt ja doch interessant … Du benutzt irgendwie RandomAccessFile (wo ich dachte, es wär erst nötig für Zeilen-Lesen-Schreiben-Modifizieren mittendrin), um das Leerstellen-Zeilen-Problem zu umgehen …!?

Das muß ich mir mal genauer 'reinziehen.
Danke einstweilen!
RoNeunzig

Dachte, es geht einfacher, weil ich ja nix eigentlich zum serialisieren oder random-accessieren usw hab’,

aber langsam dämmert mir, daß es wohl nur mir so kompliziert vorkommt und bei Euren Vorschlägen elegante Lösungen dabei sind …

Werd’ alles der Reihe nach 'mal genau studieren und dann (endlich!) ausprobieren!
Danke einstweilen
RoNeunzig
[allen Antworten ein Sternchen geben ;o)]

=Grid[read(x)][read(y)] owt
… nich’
Grid[read(x)][Grid(read(y)]
(oder was ich da falsch geschrieben hab’)

Hallo

RandomAccessFile is’ gedacht für zeilenweisen Zugriff auf
Dateien …

Ich weiß nicht, ob sie dafür gedacht ist, aber mit ihr ist es möglich direkt Integerwerte in die Datei zu schreiben. Bei anderen Klassen müsstest du die Werte in irgeneiner Form umwandeln (in die vier Byte zerlegen) oder aber wenn du sie als Zeichenkette schreibst mit einem Trennzeichen voneinander trennen.

Das brauch’ ich überhaupt nich’ … ich muß nich’ mitten in
meiner Datei Zeilen löschen, ergänzen oder sowas.
thk

Musst du ja auch nicht machen, es reicht, wenn du die Datei mit dem entsprechenden Konstruktor öffnest und die Integerwerte schreibst. Du musst ja nicht alles, was eine Klasse bietet auch wirklich nutzen! Aber sie sollte das bieten, was du nutzen willst!

Noch mal als kleine Erklärung. Du kannst im Grunde alle Klassen nutzen, die die Möglichkeit bieten Dateien zu schreiben.
Beispielsweise die Klasse FileOutputStream. Hier hast du die Möglichkeit über write() ein Array von Bytes direkt in die Datei zu schreiben. Mehr brauchst du im Grunde nicht. Wenn du die Zahl jetzt in eine Zeichenkette wandelst, dann kannst du diesen String wiederum in ein Char-Array wandeln und so in die Datei schreiben. (Der Unterschied zwischen Byte und Char ist im Grunde nur, dass ein Char einem unsigned Byte entspricht, sie haben die gleiche Größe nämlich ein Byte). Um einen einzelne Buchstaben (als Trennzeichen) zu schreiben (z.B.: „;“ oder „\n“) kannst du auch diese Funktion nutzen (Ein Buchstabe entspricht einem Char -> unsigned Byte). Wenn du die Zahlen binär schreiben möchtest, dann hast du das Problem, dass ein Integer eine Größe von vier Byte entspricht. Du müsstest also, um die write() Funktion nutzen zu können, diesen Integer in die 4 Byte zerlegen. (Beispielsweise über gezieltes Null setzen von Bits mit der UND-Operation und einer Shift-Operation -> Um der Arbeit zu entgehen empfehle ich wie gesagt RandomAccessFile.writeInt()).
Ich hoffe ich habe jetzt nicht zu viel geschrieben und dir ein bisschen helfen können.

Anmerkung: Ich glaube in manchen Fällen wird ein String automatisch als Byte-Array akzeptiert. Du müsstest also um eine Zeichenkette mit write(byte[]) zu schreiben nur den String übergeben.

mfg

lucas_d

1 Like

byte char int String …

Ich hoffe ich habe jetzt nicht zu viel geschrieben und dir ein
bisschen helfen können.

Ja, doch! … Das hilft mir sehr weiter … Meine Erfahrung mit imageio nämlich (wo einfach ein zB bild.jpg geschickt und wieder ‚abgeholt‘ wird), wo es tatsächlich trivial war, ist kein Vergleich zu den (aus meiner Sicht) ‚Komplikationen‘, die sich hier ergeben.
Ich weiß nun, daß ich etwas ‚tiefer in die Materie eindringen‘ muß. (eben wegen der verschiedenen Möglichkeiten anwendbarer (Write-Read-In-Output-Buffered-Piped-Serialized-RandomAccess-Interface-Gedöns) ~Klassen und den jeweils verfügbaren Methoden mit dem zugehörigen Datentyp-Gewimmel)

Dabei ('rumprobieren und API studieren) sind alle Eure Vorschläge sehr sehr hilfreich und wegweisend!
Zumal ich nun durch Eure Beiträge verstanden zu haben glaube, daß - obwohl mein Anliegen recht trivial erscheint - es doch ein gewisses ‚Geschick‘ erfordert diese java-Möglichkeiten … äerhh … ‚elegant‘ umzusetzen
;o))

Ps: werde beizeiten mein Ergebnis hier 'reinposten
PPs: lange Rede -> kurzer Sinn : Ich muß es nur noch MACHEN!
gruß danke
roneunzig