# zeilen in Text datei ändern



## slaveZero (19. November 2006)

hallo
ich benutze die klasse ofstream und schreibe mit dem operator<< in eine text datei sachen rein die jeweils mit einem ';' getrennt sind
jetzt würde ich gerne wissen wie ich aus der Text datei zeilen löschen kann? oder ändern?
gibts da eine methode? ich find nämlich nix
vielleicht gibts ja ne bessere möglichkeit in text dateien zu schreiben
für das auslesen benutz ich die methode getline von der klasse ifstream!


----------



## Flegmon (19. November 2006)

hi
dir bleibt wahrscheinlich nix anderes übrig, als den Inhalt der Datei zu überschreiben.
Am einfachsten ist es wohl alles einzulesen, die entsprechende zeile rauszulöschen und wieder alles zu schreiben.
Du kannst aber auch mit dem schreib cursor zur entsprechenden Zeile springen und ab dort alles überschreiben.


----------



## slaveZero (19. November 2006)

mhh schade ich dachte es würde auch anders gehen
aber naja ok dan werd ichs so machen
danke nochmals


----------



## Lemieux66 (25. Dezember 2008)

Genau bei dem habe ich auch ein Problem. Das mit dem Cursor dort hinspringen ist wahrscheinlich zu schwierig für mich aber ich habe das mal etwas geschrieben, vielleicht dass mir jemand meine Fehler verbessern kann:

```
fstream datei("Ablage.txt", ios::in);
     
    string zeile;
    int j;
    int i = 0; 

    for (j=0;j==3;j++)
    {
        while ( !datei.eof() ) 
        { 
        getline(datei, zeile); 
        i++; 
        }
    }
    
                    if (getline(cin,zeile)) 
                  {
                                     
                                     datei << zeile << endl;                      
                                     
                    
                  }
```

Jetzt habe ich mir vorgestellt, dass ich irgend wie die Zahl der Zeile eingeben kann und dannach es mir genau diese Zeile ausgibt auf den Bilschirm und ich ihn nochmals eingeben kann. 
Leider funktioniert dieser Code nicht, aber es kommt auch kein Fehler, kann mir jemand vielleicht sagen was ich vergessen habe


----------



## devDevil (26. Dezember 2008)

Du ließt einmal ein und gibst das direkt aus?! Was erwartest du von dem Code? (TIPP: Deine Bedingung in der for-Schleife ist direkt nicht erfüllt und damit wird die Schleife nie durchgegangen )


----------



## Lemieux66 (27. Dezember 2008)

Ich habe mir vorgestellt, dass 'j' die zahl ist, der zeile die ich ändern will, also das es die zeilen abzählt, also hier im beispiel 3, und ich dann an der zeile den neüen text eingeben kann und so den alten text überschreibt.
Wieso läuft die for schleife nicht durch, anfangswert ist doch '0', die schleife erhöht jedesmal um '1' bis j=3 ist, oder was hab ich da nicht verstanden?
Gruss


----------



## sheel (27. Dezember 2008)

Als Bedingung musst du schreiben j<3
Die Schleife wird durchlaufen, SOLANGE die Bedingung erfüllt ist, nicht BIS zur Erfüllung


----------



## Lemieux66 (27. Dezember 2008)

danke, habe ich nun geändert, aber leider hat es mir im .txt file die zeile immer noch nicht geändert, ich habe keine ahnung was da noch falsch ist.
kannst du mir vielleicht noch ein tipp geben?


----------



## sheel (27. Dezember 2008)

Warum probierst du eigentlcih 3 mal die ganze Datei einlesen?
statt diesem while im for wäre ein if vielleicht angebrachter


----------



## devDevil (27. Dezember 2008)

Okay erstmal die auffälligen Fehler, du wirst später feststellen das es immer noch nicht geht weil die Lese/Schreib-Zeiger nicht identisch sind, aber okay:

```
std::fstream datei("Ablage.txt", std::ios_base::in);
```
Du willst nachher was in die Datei schreiben, öffnest aber nur zum Lesen?


```
int j;
```
 brauchst du das außerhalb der Schleife? Wird der Wert jemals < 0? UND wird er jemals so groß? 

```
int i = 0;
```
 brauchst du eigtl. garnicht .... 


```
for (j=0;j==3;j++)
```
Abbruchbedingung muss durch Bedingung ersetzt werden. Und Pre-Inkrement ist (meist) schneller als Post-Inkrement.

```
{
        while ( !datei.eof() ) 
        { 
        getline(datei, zeile); 
        i++; 
        }
    }
```
 Du versuchst (auf eine falsche Weise) jedesmal die ganze Datei einzulesen?! (und i ist überflüssig ...)


```
datei << zeile << endl;
```
 Probier's mal aus mit korrigiertem Quellcode  Es wird nicht klappen  (Lese/Schreibzeiger halt )


```
#include <iostream>
#include <fstream>
#include <string>
#include <limits>

int main()
{
    std::fstream file_stream("Ablage.txt", std::ios_base::in | std::ios_base::out);
    if (!file_stream)
    {
        std::cerr << "FEHLER: Datei konnte nicht geöffnet werden!";
        return 1;
    }

    for (std::size_t i(0); i < 3; ++i)
        file_stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    std::string new_line;
    if (std::getline(std::cin, new_line)) file_stream << new_line << std::endl;
}
```


----------



## Lemieux66 (28. Dezember 2008)

Welcher Lese und Schreib Zeiger, du meinst den IOS-Base in und out
Und wie kann ich den identisch machen dass es funktioniert,ich habe nämlich überhaupt keine Ahnung was ich an dem code ändern könnte.
Denn Code denn du mir gegeben hast, verstehe ich nicht mal richtig, also wüsste ich nicht was daran ändern. Ich sehe nur dass es mir die Zeile nicht ändert.


----------



## devDevil (28. Dezember 2008)

Ändern kannst du es eh nur wenn du alles einließt, die Zeile änderst und wieder alles rausschreibst. 

ignore schmeißt nur alles was im stream ist bis zum nächsten '\n' raus. Brauchst du ja eh nicht.


----------



## Lemieux66 (28. Dezember 2008)

Eben mit dem code wo du mir gegeben hast, lese ich ja die datei ein, wo z.b. 5 zeilen text sind und dann im 'cin' gebe ich ja den text ein, dür die 3.te zeile, und danach speichert es doch den neuen text mit der eingebenen 3ten zeile über den alten text, verstehe ich doch richtig?
Und zum auslesen habe ich schon eine Funktion, aber die datei hat es ja mir nicht geändert. Und das verstehe ich nicht warum, den zum kontrollieren kann ich ja auch das wordpad beutzen.


----------



## deepthroat (29. Dezember 2008)

Hi.



			
				Lemieux66 hat gesagt.:
			
		

> Eben mit dem code wo du mir gegeben hast, lese ich ja die datei ein, wo z.b. 5 zeilen text sind und dann im 'cin' gebe ich ja den text ein, dür die 3.te zeile, und danach speichert es doch den neuen text mit der eingebenen 3ten zeile über den alten text, verstehe ich doch richtig?


Nein. Eine Datei wird nicht zeilenweise gespeichert. Du kannst eine Zeile nur ändern, wenn die neue Zeile exakt die gleiche Anzahl von Zeichen enthält wie die alte Zeile.

Wenn du auf eine beliebige Zeile zugreifen willst, dann lies die Datei am besten erstmal in eine geeignete Datenstruktur ein, die dir wahlfreien Zugriff bietet - z.B. ein std::vector.

Wenn du Zeilen ändern willst, dann ändere die Zeilen in der Datenstruktur - also im Speicher. Wenn du dann fertig bist, dann speichere die Datenstruktur komplett in der Datei ab, indem du die Datei komplett überschreibst.

Gruß

PS: Und halte dich bitte an die Netiquette. Deine Beiträge sind ja unlesbar...


----------



## Lemieux66 (6. Januar 2009)

Ich habe mich da noch im Internet erkundigt, nun habe ich gelesen, dass man  Zeile um Zeile ändern kann, indem ich zuerst bis zu der zu ändernde Zeile einlese, dann die neue Zeile eingebe und schliesslich den Rest nach der geänderten Zeile wieder einlese.

Somit muss ich nicht darauf achten, ob die neue Zeile gleich lang ist wie die alte Zeile.
Hast du damit Erfahrung, ich habe keinen blassen Schimmer wie ich das anstellen soll.


----------



## deepthroat (6. Januar 2009)

Lemieux66 hat gesagt.:


> Ich habe mich da noch im Internet erkundigt, nun habe ich gelesen, dass man  Zeile um Zeile ändern kann, indem ich zuerst bis zu der zu ändernde Zeile einlese, dann die neue Zeile eingebe und schliesslich den Rest nach der geänderten Zeile wieder einlese.
> 
> Somit muss ich nicht darauf achten, ob die neue Zeile gleich lang ist wie die alte Zeile.
> Hast du damit Erfahrung, ich habe keinen blassen Schimmer wie ich das anstellen soll.


Das funktioniert nur falls der geänderte Teil nicht zu lang ist und den noch nicht eingelesenen Teil der Datei überschreibt.

Wieso liest du die Datei denn nicht in einen std::vector ein? Ständig irgendwelche Zeilen in einem Stream zu suchen ist doch Unfug.

Gruß


----------



## Lemieux66 (6. Januar 2009)

Würde ich gerne mit deiner Methode machen, aber leider bin ich Anfänger und habe überhaupt keine Ahnung was std::vector ist, dann müsstest du mir alles "vorkauen" und ich denke die Zeit hast du nicht?!
Oder hast du die Zeit mir es zu erklären oder in den vorigen Code einzubauen?

Gruss


----------



## deepthroat (6. Januar 2009)

Lemieux66 hat gesagt.:


> Würde ich gerne mit deiner Methode machen, aber leider bin ich Anfänger und habe überhaupt keine Ahnung was std::vector ist, dann müsstest du mir alles "vorkauen" und ich denke die Zeit hast du nicht?!
> Oder hast du die Zeit mir es zu erklären oder in den vorigen Code einzubauen


Naja, du nimmst einfach den Code aus diesem Thema http://www.tutorials.de/forum/c-c/331226-aus-txt-nach-abc-ordnen.html und ersetzt jedes Vorkommen von "list" durch das Wort "vector" und schon sind die Zeilen im std::vector gespeichert.

Dann kannst du auf die Zeilen wie auf ein Array zugreifen:

```
cout << "Zeile 4: " << content[3] << endl;

content[3] = "neuer Inhalt";
```
Um den Inhalt der Datei mit völlig beliebigem anderen Inhalt zu überschreiben, solltest du die Datei am besten erstmal schließen und dann wieder mit der Option "trunc" öffnen:

```
in.close();
in.clear();

in.open("abc.txt", ios::out | ios::trunc);
```
Danach kopierst du wie gehabt alle Zeilen aus dem vector in die Datei.

\edit: Falls du das Sortieren beibehalten willst, dann mußt du für den vector die Anweisung zum Sortieren so ändern:

```
sort(content.begin(), content.end());
```
Gruß


----------



## Lemieux66 (7. Januar 2009)

Hi
Ich habe nun das probiert was du mir gesagt hast.....


```
int aendern()
{

 ifstream in("Ablage.txt");
 
  if (!in.is_open()) {
    cerr << "cannot open file.";
    return 1;
  }
 
  string line;
  vector<string> content;
 
  while (getline(in, line)) {
      content.push_back(line);
  }
  cout << "Zeile 4: " << content[3] << endl;
 
  content[3] = "neuer Inhalt";
  
  in.close();
  in.clear();
 
  in.open("Ablage.txt", ios::out | ios::trunc);
    

    
}
```

Jetzt zeigt es mir den Text aus Zeile 4 an und löscht danach alles.
Was ich jetzt nicht verstehe, bei 
	
	
	



```
content[3] = "neuer Inhalt";
```
sollte es doch mir die neue Zeile hineinschreiben,aber das tut es mir ja nicht.

Und warum muss ich alles mit 
	
	
	



```
in.clear();
```
 löschen, kann ich mit verctor nicht die einzelne Zeile ersetzen?

Und wie kopiere ich denn jetzt wieder die Zeilen hinein wenn sie gelöscht sind?

Nein, das mit sortieren will ich so lasse, das habe ich als eigene Funktion die mir zum Glück gut funktioniert.

Gruss und Danke...


----------



## deepthroat (7. Januar 2009)

Hi.

Du hast vergessen meinen Hinweis bezgl. des Speicherns zu beachten:


> Danach kopierst du wie gehabt alle Zeilen aus dem vector in die Datei.


Du solltest dir ruhig mal die Dokumentation zu den Funktionen durchlesen. Die Methode .clear() löscht nichts, sie ist dazu da den Fehlerzustand des Streams zurückzusetzen. Gelöscht wird der Inhalt der Datei durch die Angabe der Option ios::trunc beim Öffnen.

Gruß


----------



## Lemieux66 (7. Januar 2009)

So, nun hat es fast geklappt, noch ein kleiner Fehler ist drin....

Wenn ich den Text eingebe speichert es ihn, aber wenn im text eine "Lehrschlag" drin ist, dann stürzt mir das Program ab und ich weiss nicht wieso?

Besten Dank schon mal für deine Gedult.

Ich bin schon richtig stolz auf mich dass ich es so weit geschafft habe.

Hier noch der Code wenn du mir nochmals drüber schauen kannst...


```
int aendern()
{
  
  char zeilentext[101];  
  int zeile;
  
  
  
  fstream in("Ablage.txt");
 
  if (!in.is_open()) {
    cerr << "Datei kann nicht geoeffnet werden.";
    return 1;
  }
 
  string line;
  vector <string> content;
 
  cout << Abst <<"Eingabe der Zeilennummer:"; 
  cin  >> zeile;
  
                   
 
  while (getline(in, line)) {
      content.push_back(line);
    }
   cout << Abst << "Aktueller Inhalt der Zeile " << zeile << ": " << content[zeile-1] <<endl;
 
 
  cout << Abst << "Neuer Text der Zeile:";
  
  cin  >> zeilentext;
  
  content[zeile-1] = zeilentext;
  
  
  in.close();
  in.clear();
 
 
  in.open("Ablage.txt", ios::out | ios::trunc);
  
  
  while (getline(in, line)) {
      content.push_back(line);
  }
  
  
  in.clear();
  in.seekp(0);
  
 
     copy(content.begin(), content.end(),
     ostream_iterator<string>(in, "\n"));
     

    
}
```


Gruss


----------



## deepthroat (7. Januar 2009)

Lemieux66 hat gesagt.:


> Ich bin schon richtig stolz auf mich dass ich es so weit geschafft habe.


Leider hast du anscheinend nur noch überhaupt keine Ahnung von dem was du dort tust. Du müßtest dich doch mal fragen und überlegen was die einzelnen Anweisungen überhaupt bedeuten... 


Lemieux66 hat gesagt.:


> ```
> char zeilentext[101];
> ```


Da du mit C++ arbeitest, solltest du ruhig std::string verwenden:

```
string zeilentext
```
Du kannst dir die Variable aber auch gleich ganz sparen.


Lemieux66 hat gesagt.:


> ```
> cout << Abst <<"Eingabe der Zeilennummer:";
> cin  >> zeile;
> ```


Eingaben sollten immer geprüft werden. Wurde hier wirklich etwas eingelesen? Nebenbei sollte die Variable zeile nur positive Werte haben können. (unsigned)

```
if (cin >> zeile) {
   // hier kanns weitergehen...
} else {
   // fehler
   return 1;
}
```



Lemieux66 hat gesagt.:


> ```
> cout << Abst << "Aktueller Inhalt der Zeile " << zeile << ": " << content[zeile-1] <<endl;
> ```


Woher weißt du das die Eingabe der Zeile nicht zu groß war? Prüfen! (Das ist übrigens auch der Grund des Absturzes - zumindest falls du die Funktion aendern öfter aufrufst)

```
if (zeile >= content.size()) {
  // Fehler 
  return 1;
}
```



Lemieux66 hat gesagt.:


> ```
> cin  >> zeilentext;
> ```


Wie du bereits gemerkt hast liest du damit nur ein einzelnes Wort ein. Wofür könnte denn wohl die Funktion *getline* gut sein, die du bereits die ganze Zeit verwendest? ;-]

Wie gesagt, man kann die Zeile auch gleich direkt in den vector speichern:

```
if (getline(cin, content[zeile-1]) {
   // Einlesen war OK, jetzt können wir die Daten speichern
} else {
   // Fehler, Datei zu überschreiben wäre sinnlos
  return 1;
}
```


```
in.close();
  in.clear();
  
  in.open("Ablage.txt", ios::out | ios::trunc);
    
  while (getline(in, line)) {
      content.push_back(line);
  }
```
Hier hast du jetzt überhaupt nicht nachgedacht. Wozu ist diese Schleife jetzt gut? Nochmal: die Option ios::trunc bewirkt das der Inhalt der Datei beim Öffnen gelöscht wird, die Datei ist also gleich nach dem Öffnen leer, also 0 Byte groß. Welchen Sinn macht dann diese Schleife? Und was könnte die Option ios::*out* wohl bedeuten? Evtl. wird die Datei nur zur Ausgabe geöffnet... 

Gruß


----------



## Lemieux66 (8. Januar 2009)

Hallo

Ich bin es dem einfach nicht, habe lange probiert aber sehe nicht das Problem.

Habe immer wieder deine Texte durchgelesen um zu verstehe was du mir erklären willst, aber ich bin einfach noch zu unerfahren...
z.b. hier...


```
if (getline(cin, content[zeile-1]) {
   // Einlesen war OK, jetzt können wir die Daten speichern
} else {
   // Fehler, Datei zu überschreiben wäre sinnlos
  return 1;
}
```

Bei dem Befehl cin weiss ich nicht wie du meinst, dass ich den Text eingeben kann, wenn ich es so mache, kann ich nichts eingeben. Ich habe mal das verbessert was ich verstanden habe, aber sieh selbst was ich meine...


```
int aendern()
{
  
  string zeilentext;  
  int zeile;
  
  
  
  fstream in("Ablage.txt");
 
  if (!in.is_open()) {
    cerr << "Datei kann nicht geoeffnet werden.";
    return 1;
  }
 
  string line;
  vector <string> content;
 
  cout << Abst <<"Bitte die Nr. der Zeile angeben die Sie aendern moechten:"; 
  
  if (cin >> zeile) 
  {
          
  } 
      else 
      {
      // fehler
      return 1;
      }
  
                   
 
  while (getline(in, line)) {
      content.push_back(line);
  }
  
  cout << Abst << "Aktueller Inhalt der Zeile " << zeile << ": " << content[zeile-1] << endl;
 
 
  cout << Abst << "Nun geben Sie den neuen Text ein fuer die Zeile:";
  
  
  if (getline(cin >> zeilentext, content[zeile-1]))
  
  {
                  
   content[zeile-1] = zeilentext;
   
  } 
  
      else
      {
      
      return 1;
      }
  
    
  
  in.clear();
  in.seekp(0);
  
 
     copy(content.begin(), content.end(),
     ostream_iterator<string>(in, "\n"));
  
  
 
    

    
}
```



Gruss


----------



## deepthroat (8. Januar 2009)

Hi.

Bevor du nun alles wieder falsch verstehst, gebe ich offiziell auf.

```
int aendern() {
  unsigned int nr;
  string line;

  fstream file("Ablage.txt", ios::in);

  if (!file.is_open()) {
    return 1;
  }
  vector<string> content;

  while (getline(file, line)) {
    content.push_back(line);
  }

  cout << "Zeilennummer (1-" << content.size() << "): ";
  if (cin >> nr && nr >= 1 && nr <= content.size()) {
    --nr;
    cin.ignore(1 << 13, '\n');
  } else {
    return 1;
  }

  cout << "Neue Zeile: ";
  if (!getline(cin, content[nr])) {
    return 1;
  }
  
  file.close();
  file.clear();
  
  file.open("Ablage.txt", ios::out | ios::trunc);

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

  return 0;
}
```
Falls das bei dir nicht funktioniert, dann hast du noch andere Fehler im Programm.

Außerdem wäre es natürlich viel sinnvoller, falls du die Zeilen mehrfach im Programm ändern willst, die Datei gleich zu Beginn des Programms einzulesen und nur den vector zu verändern, und kurz vor Ende des Programms wieder zu speichern.

Gruß


----------



## Lemieux66 (8. Januar 2009)

Danke vielmals, die Funktion funktioniert einwandfrei.
Jetzt muss ich nur noch nachschlage was das Programm im einzelnen macht...

Das mit der Zeilenmengen Angabe finde ich auch super, wäre nicht auf die gute Idee gekommen.


Danke und Gruss


----------

