Forum: PC-Programmierung C++ Binärdatei lesen und schreiben


von A. R. (redegle)


Lesenswert?

Hallo,

ich würde gerne bei einer Binärdatei herrausfinden, wie lang diese ist.
Nur klappt das nicht so wie geplant.

Hier erstmal der Quellcode
1
fstream datei; 
2
long pos;
3
4
datei.open("C:\\Users\\Benutzername\\Desktop\\fstream\\Daten2.txt", ios::out | ios::binary); 
5
//Hier befindet sich eine Binärdatei
6
if(datei)
7
{
8
  datei.seekp(0, ios::end);
9
  pos=datei.tellp();//pos sollte nun auf das Ende zeigen, zeigt aber auf 0
10
  datei.close();
11
}
12
else
13
{
14
  cout << "Zugriff auf Datei gescheitert";
15
}
Hat jemand eine Idee, wo das Problem liegt?
Wenn ich eine Datei öffne, dort Daten hineinschreibe und dann ans Ende 
springt klappt alles normal. Aber nur mit den Daten, die ich nach dem 
öffnen geschrieben habe. Ich bin bei einer bereits bestehende Datei 
nicht in der Lage zu erkennen, wie lang diese ist.

Wenn ich beim Öffnen ios:app ergänze zeigt dies auch keinen Effekt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wenn Du die Datei mit ios::out öffnest, öffnest Du die Datei zum 
Schreiben - und damit hat sie, solange Du noch nichts hineingeschrieben 
hast, auch keinen Inhalt. Was vorher in der Datei drinstand, wird damit 
gelöscht.

von A. R. (redegle)


Lesenswert?

Danke,

das macht natürlich Sinn. Habe es mir gerade notiert, damit ich den 
Fehler kein 2tes mal mache.
Aber welcher Alternative habe ich, wenn ich überall in der Datei 
schreiben möchte.
1
ios:in  Öffnen einer Datei zum Lesen
2
ios:out  Öffnen einer Datei zum Schreiben (Alte Datei wird dabei gelöscht)
3
ios::binary  Öffnet Datei im Binärmodus. Ohne diese Angabe wird die Datei als Textdatei interpretiert.
4
ios:app  Öffnen einer Datei und positionieren des Schreibzeigers auf das Dateiende. Die neuen Daten werden immer ans Ende der Datei eingefügt, unabhängig davon ob der Schreibzeiger inzwischen neu positioniert wurde.
5
ios::ate  Öffnen einer Datei und positionieren des Schreibzeigers auf das Dateiende. Der Schreibzeiger kann bei Bedarf neu positioniert werden (seekp(...)) und die Daten werden dann an der neuen Position eingefügt.
6
ios::trunc  Öffnet eine Datei, wobei der ursprüngliche Inhalt wird verworfen.
ios::app schreibt immer ans Ende. Das bringt also nichts.
Bei ios::app und bei ios::trunc meldet mir das Programm einen Fehler.
Also wenn ich das Programm wie folgt aufbaue.
1
datei.open("C:\\Users\\Benutzername\\Desktop\\fstream\\Daten2.txt", ios::trunc | ios::binary); 
2
// ODER
3
datei.open("C:\\Users\\Benutzername\\Desktop\\fstream\\Daten2.txt", ios::ate | ios::binary);
Hierbei spielt es auch keine Rolle, ob die Datei bereits vorhanden ist 
oder nicht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

A. R. schrieb:
> Bei ios::app und bei ios::trunc meldet mir das Programm einen Fehler.

Das Programm meldete einen Fehler. Aha. Dein Programm oder der Compiler? 
Und --verflucht nochmal-- welchen Fehler?!

von Klaus W. (mfgkw)


Lesenswert?

Jedenfalls nicht das obige Programm, weil es so gar nicht kompilierbar 
ist.

von Klaus W. (mfgkw)


Lesenswert?

C++-Streams haben jeweils 2 Dateizeiger: einen zum Schreiben (put) und 
einen zum Lesen (get).
Dementsprechend gibt es seekp() und tellp() für die Schreibposition und 
seekg() und tellg() für die Leseposition.

Eben mit g++ 4.3.2 erfolgreich probiert:
1
// Time-stamp: "15.10.11 01:18 dateilaenge.cpp klaus?wachtler.de"
2
//
3
// öffnet Datei zum Lesen, positioniert ans Ende und gibt Position aus
4
5
#include <iostream>
6
#include <fstream>
7
8
int main( int nargs, char **args )
9
{
10
  std::ifstream   datei( "t.txt", std::ios::binary );
11
12
  datei.seekg( 0, std::ios::end );
13
14
  std::cout << "Position ist " << (datei.tellg()) << std::endl;
15
}

von A. R. (redegle)


Lesenswert?

Ersteinmal schonmal vielen Dank für die Hilfe.

>Das Programm meldete einen Fehler. Aha. Dein Programm oder der Compiler?
>Und --verflucht nochmal-- welchen Fehler?!

>Jedenfalls nicht das obige Programm, weil es so gar nicht kompilierbar
>ist.

Das Programm wurde erfolgreich kompiliert.
Der Rückgabewert von datei war aber 0.
Die Aussage, dass das Program einen Fehler meldet war nicht sehr 
ausführlich sorry.

Ich habe nun folgendes Programm erstellt:
1
  ifstream datei; 
2
  datei.open("C:\\Users\\Benutzername\\Desktop\\fstream\\Daten2.txt", ios::binary); 
3
  if(datei)
4
  {
5
    datei.seekg( 0, ios::end );//Sprung ans Ende
6
    long pos = datei.tellg();
7
    datei.close();
8
  }
9
  else
10
  {
11
    cout << "Zugriff auf Datei gescheitert";
12
  }
Hier klappt alles wie es soll.
Wenn ich nun ifstream durch fstream ersetzt und ios:in ergänze klappt 
auch noch alles.
1
  fstream datei; 
2
  datei.open("C:\\Users\\Benutzername\\Desktop\\fstream\\Daten2.txt", ios::binary|ios:in); 
3
  if(datei)
4
  {
5
    datei.seekg( 0, ios::end );//Sprung ans Ende
6
    long pos = datei.tellg();
7
    datei.close();
8
  }
9
  else
10
  {
11
    cout << "Zugriff auf Datei gescheitert";
12
  }
Wenn ich eine Datei komplett neu erstelle (ios::out) kann ich auch mit 
seekp() die Schreibposition ermitteln.

Ich hatte aber eigendlich gehofft, dass ich mit fstream (istream + 
ostream) eine Datei öffnen kann und dann schreiben und gleichzeitig 
lesen kann.

Also z.B.

-verbinden mit vorhandener Datei
-Daten in einer bestimmten Position einlesen
-Daten in einer bestimmten Position schreiben

Wenn ich das richtig verstanden habe muss ich ios::in angeben wenn ich 
eine Datei lesen möchte. ios::out zum schreiben (hierbei wird die alte 
Datei gelöscht). ios::binary muss ich immer angeben, da ich eine 
Binärdatei verwende. Ich hatte jetzt gehofft, dass ich ios::ate 
verwenden kann um dann zu schreiben und zu lesen oder muss ich jedes mal 
eine neue Verbindung zur Datei herstellen, wenn ich vom lesen zum 
schreiben wechseln möchte?

Ich habe auch das Problem, dass ich keine Datei verändern kann.
Verwende ich ios::binary|ios::ate bekomme ich als Rückgabewert von datei 
eine 0.

von A. R. (redegle)


Lesenswert?

Mittlerweile bin ich einen Schritt weiter.

Wenn ich eine Datei lesen und gleichzeitig schreiben möchte muss 
ios::out und ios::in gleichzeitig verwendet werden. Ios::out alleine 
würde die alte Datei neu erstellen und die alte löschen. Wenn ich 
ios::out mit ios::in verwenden möchte muss die Datei aber bereits 
existieren.

Heißt also für mich, dass ich immer zuerst überprüfen muss ob die Datei 
schon existiert. Macht es Sinn, hierzu einfach einen Lesezugriff zu 
machen?
Wenn dieser fehlschlägt existiert die Datei nicht. Oder ist dies zu 
unsicher? Wie würdet Ihr eine Datei auf Existenz prüfen?

von Klaus W. (mfgkw)


Lesenswert?

Schon mal mit Doku probiert?
Öffnen zun Schreiben und Lesen geht, aber wenn du hier stückweise damit 
rausrückst, was du eigentlich vorhast, ist ein Buch die bessere Wahl.

Und lass das mit using namespace std, das geht schief und ist grottiger 
Stil (auch wenn es viele machen).

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.
Lade...