Forum: PC-Programmierung Spaltenweise in ein File schreiben C


von Icke_Wa (Gast)


Lesenswert?

Tachesacht,

ich versuche gerade mir ein paar Werte zum debuggen auszugeben. Das 
Programm errechnet nen Haufen Werte erst fuer x=10 rechne, rechne 
,rechne dann fuer x=20 , rechne ,rechne ,rechne fuer x = 30 usw.

Jetzt haette ich gerne dass das Programm die Werte fuer x=10 in die 
erste Spalte schreibt, x=20 in die zweite Spalte usw.
Momentan arbeite ich mit fprintf, schreibe die Werte fuer x=10 runter:

fprintf(file, "%d", x10);

wollte dann den Schreibpointer via:
fseek(file, 0L, SEEK_SET);


wieder an den Anfang setzen und dann via
fprintf(file, "\t %d", x20);
in die naechste Spalte schreiben.

Dummerweise scheint er den fseekt Befehl vollkommen zu ignorieren. Das 
Ergebnis im file sieht quasi so aus:

x10
x10
x10
x10
x10
x10
x10
x10
     x20
     x20
     x20
     x20
     x20
     x20
     x20
         x30
         x30
         x30
         x30
         x30
         x30

jemand ne idee wie ich das in diese Form bekomme:

x10   x20   x30
x10   x20   x30
x10   x20   x30
x10   x20   x30
x10   x20   x30
x10   x20   x30

Danke schonmal fuer die Hilfe!

von Vlad T. (vlad_tepesch)


Lesenswert?

vergiss das mit dem seek.
ordne deine Berechnungen so, dass du gleich alle 3 Daten asugeben 
kannst, oder - sollte das nicht gehen - halte sie solange im Speicher, 
wie nötig.
bei extrem großen Datenmengen schreibst du ebend 3 Files und generierst 
zum schluss das mehrspaltige

von Mark B. (markbrandis)


Lesenswert?

Mach's im Hauptspeicher so, wie Du es haben willst, und dann schreib es 
einfach in einem Rutsch in die Datei rein.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Icke_Wa schrieb:
> Dummerweise scheint er den fseekt Befehl vollkommen zu ignorieren.

Das wundert mich etwas. Kann es sein, dass das verwendete Filesystem
keine Seeks unterstützt? Eigentlich hätte ich erwartet, dass nach dem
fseek die bereits bestehenden Daten einfach überschrieben werden, wobei
das natürlich auch nicht das ist, was man will.

Hier ist eine korrigierte Version mit fseek, die zumindest hier unter
Linux funktioniert:
1
#include <stdio.h>
2
3
#define ANZ_ZEILEN 10
4
#define ANZ_SPALTEN 3
5
#define SPALTENBREITE 4
6
#define ANZ_ZEILENENDE 1 // 1 für Linux, 2 für DOS & Co
7
8
int main(void) {
9
  FILE *fp = fopen("log", "w");
10
  long pos;
11
  int s, z;
12
13
  for(s=0; s<ANZ_SPALTEN; s++) {
14
    for(z=0; z<ANZ_ZEILEN; z++) {
15
      pos = z*(ANZ_SPALTEN*SPALTENBREITE+ANZ_ZEILENENDE)+SPALTENBREITE*s;
16
      fseek(fp, pos, SEEK_SET);
17
      fprintf(fp, "%*d", SPALTENBREITE, s*z);
18
      if(s==ANZ_SPALTEN-1)
19
        fprintf(fp, "\n");
20
    }
21
  }
22
  fclose(fp);
23
  return 0;
24
}

Ergebnis:
1
   0   0   0
2
   0   1   2
3
   0   2   4
4
   0   3   6
5
   0   4   8
6
   0   5  10
7
   0   6  12
8
   0   7  14
9
   0   8  16
10
   0   9  18

von Icke_Wa (Gast)


Lesenswert?

Hm ... also den Code so umaendern ... ja gehen tut das schon, aber ich 
wollte damit frueher oder spaeter auch Messwerte auslesen und sortieren 
um mir das ganze bloede Excell rumgeklicker zu spahren.

@ Yalu. Das alles einfach ueberschrieben wird, war auch eigentlich meine 
Mindesterwartung, aber irgedwie mag der das wohl nich. Ich nutze hier 
Visual C++ auf Win. XP ... glaube mit diesem Standartcompiler, so von 
wegen System.

Deine Code Yalu versteh ich noch nicht ganz. pos wird doch nach dem 
ersten durchlauf (s=0 und z=1) zu 13. Wo schreibt der denn mit pos=13 
hin?

von Peter II (Gast)


Lesenswert?

du solltest sich erstmal im klaren sein was eine Datei ist. Dort gibt es 
keine spalten. Dort gibt es auch keine Zeilen. Das ganze ist nur ein 
ansammlung von bytes. Man kann also nichts "einfügen" dann dafür muss 
man alles nach hinten schrieben. Yalu X. lässt also immer schon platz 
für die anderen Daten damit er sie später einfügen kann. Das ganze geht 
zwar ist aber extrem unflexibel. Schreibt die Daten einfach in eine 
Dantebank dann kannst du sie in jeden möglichen form auswerten.

von Karl H. (kbuchegg)


Lesenswert?

Icke_Wa schrieb:

> @ Yalu. Das alles einfach ueberschrieben wird, war auch eigentlich meine
> Mindesterwartung,

langsam.
Ohne zusätzliches Gedöhns funktioniert das nicht so, wie du dir das 
vorstellst. Überschreiben heißt auch wirklich überschreiben.
D.h. wenn du mit fseek zurück gehst an die Zeile, dann wird auch die 
Information am Anfang dieser Zeile überschrieben!

Du kannst in einem Textfile nicht so einfach Zeilen verlängern (oder 
verkürzen). Dazu muss nämlich alles dahinterliegende im File 
entsprechend verschoben werden, was aber durch einfaches Überschreiben 
nicht passiert.

d.h. du musst im File als allererstes dir Zeilen mit einer definierten 
Länge schaffen, die Leerzeichen enthalten, damit du in den späteren 
Durchgängen schon den Platz hast, an dem überschrieben werden kann.

> Visual C++ auf Win. XP ... glaube mit diesem Standartcompiler, so von
> wegen System.

Der fseek funktioniert schon.

Nur ist die ganze Herangehensweise für Textfiles nicht wirklich gut 
geeignet.

Du musst dir ein Textfile wie eines von den alten Tonbändern vorstellen. 
Wenn du da Musik aufzeichnest und hinterher zwischen 2 Musikstücke ein 
drittes einfügen willst, dann reicht es nicht einfach das Tonband auf 
den Anfang des 2. Stückes zu setzen und dort dann das 3. aufzunehmen! Du 
überschreibst dir damit zwangsläufig das vorher dort gespeicherte 2. 
Stück. Wenn du nicht bei der ersten Aufnahme zwischen 1.tem und 2.tem 
Stück entsprechend Platz gelassen hast um dort dann das 3. Stück 
hinterher einsetzen zu können, hast du mit Zitronen gehandelt.

Und genau das macht Yalu: er lässt sich entsprechend Platz und dreht das 
ganze so hin, dass er im "Text" an die entsprechende Position seekt, in 
der die x-te Spalte der y-ten Zeile beginnt. Beginnen muss, weil er 
weiß, wieviele Spalten es sind und wie breit jede Spalte ist (und am 
Zeilenende ein \n Zeichen steht)


Und PS: Ein Tabulator, \t, ist ein Zeichen wie jedes andere. Dadurch, 
dass du einen \t aufs File schreibst, überspringst du nichts. Du 
schreibst ein \t Zeichen aufs File, mehr tust du damit nicht. Erst das 
Programm, welches die Daten anzeigt (bzw. dann der Display Treiber), 
wertet dem Tab eine spezielle Bedeutung zu und schickt den Cursor ein 
paar Zeichen nach rechts.

von Rolf M. (rmagnus)


Lesenswert?

So ein Seek ist in Textdateien übrigens offiziell eigentlich gar nicht 
erlaubt.

von Klaus (Gast)


Lesenswert?

Rolf Magnus schrieb:
> So ein Seek ist in Textdateien übrigens offiziell eigentlich gar nicht
> erlaubt.

Diesen Paragraphen des BGB hat der Europäische Gerichtshof mittlerweile 
gekippt.

von Rolf M. (rmagnus)


Lesenswert?

Das steht nicht im BGB, sondern in der ISO-Norm. Mit "offiziell nicht 
erlaubt" meinte ich eher, daß es bei den meisten Compilern wohl 
funktionieren dürfte, aber eigentlich gegen die ISO-Norm verstößt. Hier 
die entsprechende Passage daraus:

"For a text stream, either offset shall be zero, or offset shall be a
value returned by an earlier successful call to the ftell function on a
stream associated with the same file and whence shall be SEEK_SET."

von Yalu X. (yalu) (Moderator)


Lesenswert?

Rolf Magnus schrieb:
> "For a text stream, either offset shall be zero, or offset shall be a
> value returned by an earlier successful call to the ftell function on a
> stream associated with the same file and whence shall be SEEK_SET."

Ja, das habe ich auch gesehen, nachdem ich den obigen Beitrag abge-
schickt hatte. Ich nehme an, diese Einschränkung wurde gemacht, um
Verwirrung bei unterschiedlichen Zeilenend- und Zeichencodierungen zu
vermeiden, glaube auf der anderen Seite aber nicht, dass sich die Lauf-
zeitumgebung merkt, welche Offset schon einmal von ftell zurückgegeben
worden sind und damit "legal" sind. Somit ist das obige Beispielprogramm
zwar bäh, sollte aber trotzdem funktionieren (unter Linux mit GCC tat es
das ja auch).

Besser wäre es aber, die Datei im Binärmodus zu öffnen und die Behand-
lung von Zeilenenden explizit auszuprogrammieren.

von Mark B. (markbrandis)


Lesenswert?

Mark Brandis schrieb:
> Mach's im Hauptspeicher so, wie Du es haben willst, und dann schreib es
> einfach in einem Rutsch in die Datei rein.

Ich kann es noch ein paar mal wiederholen :-)

von MaWin (Gast)


Lesenswert?

> unter Linux mit GCC tat es das ja auch

Unter Windows mit CRLF als Zeilentrenner funktioniert es natürlich 
nicht.

Aber portabel schreiben fällt ja unter fortgeschrittenes Programmieren.

von Yalu X. (yalu) (Moderator)


Lesenswert?

MaWin schrieb:
>> unter Linux mit GCC tat es das ja auch
>
> Unter Windows mit CRLF als Zeilentrenner funktioniert es natürlich
> nicht.

Hast du's probiert (mit #define ANZ_ZEILENENDE 2)? Wenn es dich stört,
dass das Makro an das jeweilige Betriebssystem angepasst werden muss,
kannst du die Unterscheidung gerne mit "#ifdef WIN32" o.ä. automatisie-
ren.

Ich habe ja auch nichts gegen die Lösung, bei der die auszugebenden
Daten erst einmal in einem großen Array zwischengespeichert werden. Aber
zum einen ist das nur bis zu einer gewissen Datenmenge möglich bzw.
sinnvoll, zum anderen wollte ich den Ansatz des TE, die Datei direkt zu
beschreiben, zu Ende führen.

von MaWin (Gast)


Lesenswert?

> #define ANZ_ZEILENENDE 1 // 1 für Linux, 2 für DOS & Co

Oh, super.

Ich hab halt gedacht, ab SPALTENBREITE Ziffern in der Zahle der ersten 
Spalte wird die erste Ziffer überschrieben.

von Karl H. (kbuchegg)


Lesenswert?

Yalu X. schrieb:

> Ich habe ja auch nichts gegen die Lösung, bei der die auszugebenden
> Daten erst einmal in einem großen Array zwischengespeichert werden. Aber
> zum einen ist das nur bis zu einer gewissen Datenmenge möglich bzw.
> sinnvoll, zum anderen wollte ich den Ansatz des TE, die Datei direkt zu
> beschreiben, zu Ende führen.


Ändert auch nix daran, dass der ganze Ansatz des TO nicht viel taugt.

> aber ich wollte damit frueher oder spaeter auch Messwerte auslesen
> und sortieren um mir das ganze bloede Excell rumgeklicker zu spahren.

er wird die Daten sowieso in ein anderes Programm einlesen. Sinnlos da 
jetzt Klimmzüge zu machen um ein bestimmtes Datenformat hinzukriegen, 
dass dann eh keiner mehr braucht.

von Mark B. (markbrandis)


Lesenswert?

Yalu X. schrieb:
> Ich habe ja auch nichts gegen die Lösung, bei der die auszugebenden
> Daten erst einmal in einem großen Array zwischengespeichert werden. Aber
> zum einen ist das nur bis zu einer gewissen Datenmenge möglich bzw.
> sinnvoll, zum anderen wollte ich den Ansatz des TE, die Datei direkt zu
> beschreiben, zu Ende führen.

Wenn die Datenmenge tatsächlich richtig groß wird, sollte man wohl 
besser auf ein DBMS umsteigen, anstatt selbst händisch in Dateien 
herumzufuhrwerken. Da wird man doch nicht glücklich bei.

Und mit SQLite macht es sogar auch bei nicht so großen Datenmengen schon 
Spaß ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.