# wie in C/C++ eine "tabellarische" Textdatei erstellen



## busenbach (8. August 2007)

Hallo,
ich bin neu hier und habe eine Frage. Ich habe leider nichts dergleichen im Forum gefunden.

------------------------
Ich habe viele verschiedene Daten (Zahlen, Text) und möchte gerne diese in eine Textdatei reinschreiben. Generell kein Problem, "nacheinander" funktioniert es prima

-->Beispiel wenn ich es Zeile für Zele nacheinander mache:
1      2      3      4
a      b      c      d
1.1   2.2    3.3   4.4


Jetzt aber brauche ich aber die Daten in tabellarischer Form
-->Beispiel für tabellarisch:
1  a  1.1
2  b  2.2
3  c  3.3
4  d  4.4


Man beachte, dass ich nicht alles auf einmal reinschreibe, die Datei muss immer wieder mal geöffnet werden und reingeschrieben werden.
--------meine Proleme---------
**Bei C++ war das generelle Problem, dass wenn ich die Datei frisch öffne der Inhalt auch gleich "sofort" wieder gelöscht ist

ofstream outf("output.txt");       //Datei öffnen
outf<<DATA;                          //Daten beliebig reinschreiben
outf.close();                            //Datei schließen

**Bei C benutze ich "fprintf" und weiss nicht wie ich an das Ende der Zeile springen kann um die aktuellen Daten reinzuschrieben und gleich danach wieder in die neue Zeile runter zu gehen und da das Ende zu erreichen für die nachfolgenden Daten (es soll dabei nichts gelöscht werden)


Hoffe habe mich verständlich ausgedrückt. Kann mir da einer Helfen, wenn möglich mit Beispiel? Wie kann ich in der Textdatei an vorgesehenen Orten springen um neue Daten reinzuschreiben OHNE dabei das bestehende zu löschen!!

mfg


----------



## Faller (8. August 2007)

also in c würde ich nach dem zeilen ende  (suchen indem man eine ziele leist).

dann mit "seek" ein zeichen zurück. (um das zeilen ende zu überschreiben).

und dann mit fprintf normal schreiben.

ich hoffe du woltest einen lösungsansatz haben.

mfg Faller


----------



## busenbach (8. August 2007)

Faller hat gesagt.:


> also in c würde ich nach dem zeilen ende  (suchen indem man eine ziele leist).
> 
> dann mit "seek" ein zeichen zurück. (um das zeilen ende zu überschreiben).
> 
> ...



naja, ein kleines Anwendungs-Beispiel wäre mir schon lieb
Zu diesem seek hatte ich mal was gefunden (http://www.cpp-entwicklung.de/cpplinux3/cpp_main/cpp_mainch3.html) aber ich konnte damit nicht viel anfangen (ist das nicht c++?) Wie wende ich das korrekt an, dass ich am Ende der Zeile bin OHNE das alles davor gelöscht wird! 
Das Problem bei mir war, dass dennoch alles schlichtweg gelöscht wurde trotz seek


----------



## busenbach (8. August 2007)

Faller hat gesagt.:


> also in c würde ich nach dem zeilen ende  (suchen indem man eine ziele leist).
> 
> dann mit "seek" ein zeichen zurück. (um das zeilen ende zu überschreiben).
> 
> ...




-->übrigens, danke für die schnelle Antwort, warja RuckiZucki
was auch möglich wäre: 
Wie kann ich Schritt für Schritt jedes einzelne Zeichen durchzählen bis ich meine Trennmarkierung erreicht habe (in meinem fall ein TAB-Abstand --> '\t')
Da schlage ich mich grad mit durch.... (vielleicht finde ich ja noch was zu seek)


----------



## busenbach (8. August 2007)

ne, probiere hier schon fast den ganzen Tag wahllos jede mögliche Alternative aus, aber es klappt einfach nicht...
Kann mir jemand helfen Daten tabellarisch ein eine Textdatei einzugeben "ohne" dass die vorher geschriebenen Daten gelöscht werden.


INFO am Rande: Ich gebe immer TYP-weise die Daten ein, z.B.:
A  B  C  ...
A  B  C  ...
A  B  C  ...
erst die A-Daten, dann die B-Daten, dann die C.... usw
es soll immer hintendrann gesetzt werden

mfg


----------



## deepthroat (8. August 2007)

Hi.

Die einzige portable Möglichkeit Daten in einer Datei zu ändern, ist die Daten auszulesen, zu ändern und dann die komplette Datei nochmal abzuspeichern.

Lies doch die Datei einfach zeilenweise ein und speichere die Zeilen in einen std::vector. Wenn du nun etwas an eine Zeile anfügen willst geht das ganz einfach. Wenn du fertig bist schreibst du die Daten komplett wieder in die Datei.

Du solltest die Datei allerdings dann im Schreiben+Lesen Modus öffnen:
	
	
	



```
fstream datei("xyz.txt", ios::in | ios::out);
```

Gruß


----------



## busenbach (8. August 2007)

deepthroat hat gesagt.:


> Hi.
> 
> Die einzige portable Möglichkeit Daten in einer Datei zu ändern, ist die Daten auszulesen, zu ändern und dann die komplette Datei nochmal abzuspeichern.
> 
> ...



ja, das habe ich mittlerweile auch so gesehen, dass ich wohl erst die ganze Zeile einlesen muss, am Ende meine neuen Daten dranhänge und dann diese verlängerte Zeile über die Alte drüberschreibe. Dann gehts mit der nächsten Zeile weiter...

->Bei C++ habe ich das Problem, dass sofort "ALLES" weg ist sobald ich auch nur die Datei öffne. 
->Bei C schaff ich die Kopiervporgänge nicht

Was ich auch absolut nicht geschafft hatte war Daten "dranzuhängen", ich hatte alles in einem char-Array drin und weiss nicht wie ich da was hintendran tun kann.

Was hast du mit "std::vector" gemeint? wie geht man da vor?
mfg


----------



## deepthroat (8. August 2007)

busenbach hat gesagt.:


> ja, das habe ich mittlerweile auch so gesehen, dass ich wohl erst die ganze Zeile einlesen muss, am Ende meine neuen Daten dranhänge und dann diese verlängerte Zeile über die Alte drüberschreibe. Dann gehts mit der nächsten Zeile weiter...


Das geht so nicht. Du kannst nicht einfach mitten in einer Datei irgendwelche Daten einfügen - du kannst so höchstens Zeichen überschreiben, aber die Anzahl der Zeichen in der Datei wird sich nicht ändern, es sei denn du schreibst an das Ende der Datei noch etwas dran.



busenbach hat gesagt.:


> ->Bei C++ habe ich das Problem, dass sofort "ALLES" weg ist sobald ich auch nur die Datei öffne.


Ja, das ist ganz normal wenn du einen ofstream benutzt. Dabei wird die Datei im "truncate" Modus geöffnet - d.h. sie wird erstellt wenn sie noch nicht existiert - falls sie bereits existiert wird die Größe der Datei auf 0 Byte gesetzt.


busenbach hat gesagt.:


> Was hast du mit "std::vector" gemeint? wie geht man da vor?


Man liest alle Zeilen suchen: "zeilenweise einlesen") in einen std::vector mit Hilfe der push_back Methode ein, und modifiziert dann die Zeilen im vector (am einfachsten womögilch mit einem std:stringstream) und schreibt dann die Daten komplett wieder in die Datei.

Gruß


----------



## matthiasz (9. August 2007)

Versuche einfach mit fopen und fclose zu arbeiten. Bei fopen kannst Du kannst du den Mode a für append verwenden. Ich hoffe das hilft Dir weiter


----------



## deepthroat (9. August 2007)

matthiasz hat gesagt.:


> Versuche einfach mit fopen und fclose zu arbeiten. Bei fopen kannst Du kannst du den Mode a für append verwenden. Ich hoffe das hilft Dir weiter


Nein, das hilft ihm nicht weiter. Wenn du das Thema aufmerksam verfolgt hättest, wüßtest du, dass er keine Daten an die Datei anhängen möchte, sondern Daten an einer beliebigen Stelle in der Datei einfügen will. In C++ kann man genauso eine Datei im "append" Modus öffnen wie in C - das führt doch aber zu nichts. Es macht keinen Unterschied ob man nun C oder C++ verwendet. In C++ ist nur die Verwaltung der Daten durch die Standard-Klassen deutlich einfacher als mit C.

Gruß


----------



## busenbach (9. August 2007)

So, habs endlich geschafft!
Hier meine Lösung:

---------------------------------------------
void main()
{
	char buffer[1000];		//Buffer um Zeilen zu speichern
	fstream  inf("output.txt");	//zum rauslesen aus Textdatei
	fstream outf("output.txt");	//zum reinschreiben in Textdatei

	for(int i=0; i<AnzahlZeilen; i++)			
	{
		inf.getline(buffer,1000);	//buffer = aktuelle Zeile
		strcat(buffer, "TESTEN");            //buffer = buffer + "TESTEN"
		outf << buffer <<"\t" <<endl;       //ausgabe buffer (neu)
	}

                cout<<"TESTEN in \"output.txt\" hinzugefügt" <<endl<<endl;
	outf.close();			
	inf.close();					
}
---------------------------------------------

ACHTUNG: Am Ende der Datei sollte eine leere Zeile sein
RESUME: Immer am Ende der Zeile wird "TESTEN" hinzugefügt und so kann man jede einzelne Zeile durchgehen

Wenn jemand irgendwelche Verbesserungsvorschläge hat: Nur her damit!
gruß


----------



## deepthroat (9. August 2007)

Hi.

Ist eine nette Idee - aber keinesfalls portabel und es gibt keine Garantie das es überhaupt funktioniert. Bei mir wird z.B. nach ein paar Durchläufen die letzte Zeile überschrieben.

Man sollte auf eine Datei höchstens 1 schreibenden Stream geöffnet haben *oder* einen bzw. mehrere lesende Streams.

Ich hab mal schnell was geschrieben:

```
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <iomanip>

#include <cstdlib>

using namespace std;

int main() {
  srand(time(0));   // Zufallszahlen-Sequenz verändern

  // Datei zum Lesen+Schreiben öffnen
  fstream file("tab.txt", ios::out | ios::in);
  
  if (file.is_open()) {
    string line;
    vector<string> lines;
    
    // erstmal die Datei zeilenweise in den Vektor "lines" einlesen.
    while (getline(file, line)) {
      lines.push_back(line);
    }
    
    // {- hier werden die Zeilen verändert. -}
    for (int i = 0; i < lines.size(); ++i) {
      ostringstream formatter;
    
      // an jede Zeile wird ein Leerzeichen und eine Zufallszahl (formatiert) angefügt
      formatter << " " << setw(7) << rand();

      lines[i] += formatter.str();
    }

    file.clear(); // Streamstatus wieder auf "good" setzen
    file.seekp(0); // den Schreibcursor der Datei auf den Dateianfang setzen
    
    // die Elemente des Vektors mit \n getrennt in die Datei kopieren (überschreibt alten Inhalt)
    copy(lines.begin(), lines.end(),
	 ostream_iterator<string>(file, "\n"));    
    
    file.close(); // wieder ordentlich schliessen :)
  } else {
    // Datei existiert nicht oder konnte nicht zum Schreiben+Lesen geöffnet werden.
    cerr << "couldnt open file." << endl;

    return 1;
  }
}
```

Die main Funktion *muss* übrigens int zurückgeben.

Gruß


----------



## busenbach (9. August 2007)

@deepthroat
jo, da ist irgendwo ein Wurm... es funktioniert aber ab mehreren 100 Zahlen kommt das Programm hin und wieder zum Stolpern...

uiui, deins sieht aber komplex aus (für mich zumindest  ). Werde mich mal da dransetzen, falls du paar coments dahinter setzen könntest wäre das super.
greetings


EDIT: wo gebe ich den meine Daten ein? damit diese drangefügt werden können?


----------



## deepthroat (9. August 2007)

busenbach hat gesagt.:


> falls du paar coments dahinter setzen könntest wäre das super.


Ok, hab ich gemacht.

Gruß


----------



## busenbach (9. August 2007)

deepthroat hat gesagt.:


> Ok, hab ich gemacht.
> 
> Gruß



yeah! habs mal ausprobiert und das klappt ja tadellos Es spielt auch keine Rolle ob man integer, double oder string hat oder so, das wird ja alles automatisch umgewandelt. Super danke!!


aber was ich nicht so ganz verstanden habe sinde folgende Zeilen:


```
1) lines[i] += formatter.str();
```

-was bedeutet das ".str()" am Ende?




```
2) copy(lines.begin(), lines.end(),     ostream_iterator<string>(file, "\n"));
```

-schätze mal am die ersten beiden Ausdrücke bedeuten von ANFANG bis ENDE im Vektor
-aber wie kann man den Rest verstehen da erkenne ich nichts heraus (iterator?)


merci nochmal


----------



## deepthroat (10. August 2007)

Hi.





busenbach hat gesagt.:


> aber was ich nicht so ganz verstanden habe sinde folgende Zeilen:
> 
> ```
> lines[i] += formatter.str();
> ...


formatter ist vom Typ std::ostringstream und diese Klasse (siehe http://www.cplusplus.com/reference/iostream/ostringstream/) besitzt die Methode str() um den durch die Ausgabe-Streamoperationen erstellten String zu bekommen.

Für die Klasse std::string gibt es einen += Operator der nichts anderes macht als die Methode append(string) aufzurufen. Man hätte auch schreiben können:
	
	
	



```
lines[i].append(formatter.str());
```



busenbach hat gesagt.:


> 2) copy(lines.begin(), lines.end(),     ostream_iterator<string>(file, "\n"));
> 
> -schätze mal am die ersten beiden Ausdrücke bedeuten von ANFANG bis ENDE im Vektor


Ja, im Grunde schon. Die Methoden begin() und end() liefern jeweils Iteratoren auf das erste bzw. hinter das letzte Element des Vektors.


busenbach hat gesagt.:


> -aber wie kann man den Rest verstehen da erkenne ich nichts heraus (iterator?)


std:stream_iterator ist eine Hilfsklasse aus der Standard Template Bibliothek die einen Iterator für einen Stream und einem bestimmten Typ zur Verfügung stellt.

Für das Konzept eines Iterators siehe http://de.wikipedia.org/wiki/Iterator.

Ansonsten kann ich dir empfehlen ein gutes C++ Buch zu lesen - es lohnt sich 

Gruß


----------

