C-Programmierung , Umgang mit Binär Files ?

Hallo,

Ich habe ein Problem beim Schreiben eines C-Programms, das ich selbst nicht lösen kann.
Es geht darum das ich in einer Binär Datei nach einem String suchen möchte (der warscheinlich mehrmals vorkommt) und ihn jeweils durch Blanks überschreiben will. (Datei und Datei.neu müssen nach dem Vorgang gleich groß sein)
Mein Problem ist das ich zwar weiss wie das mit Textfiles geht, und es da auch schon geschafft habe etwas ähnliches zu tun, aber bei Binärfiles finde ich keine Lösung.
Das Program arbeitet im Moment so:

  • Den Dateinamen und den zu suchenden/ersetzenden String bekommt
    es über die Eingabeaufforderung (start dateiname string)
  • Die Datei(.qqt) wird im Binär Mode zum Lesen geöffnet und eine zweite zum schreiben (Datei.qqt.neu) erstellt.
  • Danach gibt es momentan noch ein paar ausgaben zu testzwecken
    aus (diese stimmen normalerweise immer)
  • Nun beginnt der eigentliche Suchvorgang
  • Die Datei wird Zeilenweise eingelesen
  • Die zuletzt eingelesene Zeile wird nach dem String durchsucht
  • Wird der String gefunden wird er durch Blanks überschrieben
  • Danach wird die bereinigte Zeile in die neue Datei geschrieben

Das Problem ist, das die neue Datei größer ist (da sie Nullen an stellen enthällt an der die original Datei keine enthällt).
Ausserdem sieht es so aus als ob die jeweilige Zeile schon beim Einlesen (bzw. vor dem eigentlichen Suchvorgang) verändert werden würde da der zu suchende string obwohl er im original vorhanden ist nicht gefunden wird und in der neuen Datei mit Nullen bzw. Blanks vorkommt. (ich hab keine ahnung wieso)

Also meine Frage im Prinzip:
Kann mir jemand sagen wie ich das ganze mit Binärfiles am besten mache oder mir sagen wo ich einen Fehler in meinem Programm habe
und wie ich diesen beheben kann ?

Ich bin für jede nützliche Antwort wirklich dankbar,
MfG,
Grand Moobiey

Ich hoffe niemand ist sauer wenn ich meinen Sourcecode zum überprüfen (als Beispiel) anfüge.
Zum testen des Programms bzw. um den Fehler zu sehen könnt ihr im Prinzip jedes beliebige Binärfile benutzen. Zu beachten ist jedoch das das Programm nach der Datei „Dateiname.qqt“ sucht.
Programm aufruf einfach über (Programmname datei string).

#include
#include
#include

int main(int argc, char *argv [])
{

//Erstellen der Variablen
//name wird der String genannt nachdem
//gesucht werden soll
//-------------------------------------
struct stat statbuf;
FILE *file1;
FILE *file2;
char filename[15], *line, *name = argv[2], *result;
int namelenght = strlen(name);
int counter = 0;
int linelenght;

strcpy(filename, argv[1]);
strcpy(name, argv[2]);

//Öffnen der Dateien
//Anzeigen der Benutzten Werte zwecks Überprüfung
//-----------------------------------------------
file1 = fopen(strcat(filename,".qqt"), „rb“);
printf("%s, %s, %d\n", filename, name, namelenght);
stat(filename, &statbuf);
printf(„FSize: %ld\n“, statbuf.st_size);

file2 = fopen(strcat(filename,".neu"), „wb“);

//Länge des zu suchenden Strings
//-------------------------------
namelenght = strlen(name);

//Nochmal ausgeben der Werte
//---------------------------
printf("%s, %s, %d\n", filename, name, namelenght);

if (file1 == NULL)
{
printf(„Fehler beim oeffnen der Datei.\n“);
return 1;
}

/* Datei zeilenweise einlesen und nach
String durchsuchen.
Wenn String gefunden --> durch Blanks ersetzen
und weitersuchen.
Bei Zeilenende mit nächster Zeile
fortfahren ansonsten Program beenden. */

while ((fgets(line, sizeof(line), file1)) != NULL)
{
printf("%s", line);

while((result = strstr(line, name)) != NULL)
{
memset(result, ’ ', namelenght);
// printf("%s", result);
}
linelenght = strlen(line);
printf("%d", linelenght);
fwrite(line, sizeof(line), 1, file2);
//fprintf(file2, „%s“, line);
//if ((strstr(line, „\n“)) == NULL)
// { fprintf(file2, „\n“); }

}
fclose(file1);
fclose(file2);
return 0;
}

Hallo!

Achtung! Bei Binärdateien darfst Du nicht fgets verwenden.

Hier wäre ein erster Ansatz:

  1. Dein Datei-öffnen stimmt genz genau
  2. jetzt ermittle die Dateigröße mit fseek und ftell
  3. verwende fread um die Daten zu lesen
  4. Datei schließen
  5. suchen und ersetzen
  6. Daten wieder in eine Datei schreiben (fwrite)

Der Grund:
eine Binärdatei kann mehrere Kombinationen von + enthalten, die von fgets herausgefiltert werden! außerdem könnten andere Kombinationen falsch interpretiert werden.

Den obigen Ansatz kannst Du nur dann verwenden, wenn die Datei nicht allzugroß ist. Ansonsten müßtest Du die Datei in mehrere Blöcke unterteilen. Dabei kann es passieren, daß Dein Suchstring unterteilt wird!

Ich hoffe ich konnte Dir etwas helfen!

Max

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Moin,

  • Die Datei(.qqt) wird im Binär Mode zum Lesen geöffnet und
    eine zweite zum schreiben (Datei.qqt.neu) erstellt.
  • Die Datei wird Zeilenweise eingelesen

Binärdateien haben niemals Zeilen. Es kann höchstens den Anschein haben, sie hätten welche, was dann erst recht zu Problemen führen kann. Ich würde

  • die Datei binär öffnen
  • die Dateigröße ermitteln
  • einen Buffer der entsprechnden Größe allozieren
  • die Datei in den Buffer lesen
  • die Datei schleießen
  • die Datei im Buffer bearbeiten
  • die Ausgabedatei erstellen
  • den Buffer in die Ausgabedatei schreiben.
  • die Ausgabedatei schließen
  • den allozierten Bereich freigeben (nur damit sich keine schlechten Angewohnheiten einprägen)

Wenn Du die Datei binär bearbeitet hast und immer noch Fehler auftreten, kannst Du Dich nochmal melden.

Hast Du einen Lehrer? Ich würde ein paar Kleinigkeiten anders machen, zB.:

FILE *file1;
FILE *file2;

Bessere Namen wählen.

file1 = fopen(strcat(filename,".qqt"), „rb“);
if (file1 == NULL)

Die Überprüfung erfolgt zu spät. Die übliche Konstruktion ist:
if ((file1 = fopen(…)) == NULL)
{
//Fehlerbehandlung
}
Das sieht zwar erstmal kompliziert aus, wird aber noch an anderen Stellen gebraucht.

Thorsten

file1 = fopen(strcat(filename,".qqt"), „rb“);
if (file1 == NULL)

Die Überprüfung erfolgt zu spät. Die übliche Konstruktion ist:
if ((file1 = fopen(…)) == NULL)

Frage, warum soll bei der obigen (leichter verständlicheren) Variante die Prüfung „zu spät erfolgen?“.

Beide Varianten resultieren meiner Meinung nach in exakt dem selben Ergebnis!

Max

Hallo Thorsten

file1 = fopen(strcat(filename,".qqt"), „rb“);
if (file1 == NULL)

Die Überprüfung erfolgt zu spät. Die übliche Konstruktion ist:
if ((file1 = fopen(…)) == NULL)
{
//Fehlerbehandlung
}

Ich muss dir hier etwas wiedersprechen; ein guter Compiler wird in beiden Fällen genau den gleichen Code erzeugen !
Die 2. Konstruktion hat lediglich den Vorteil, dass nicht versehentlich Befehle zwischen fopen() und if eingefügt werden können, womöglich dann noch solche welche den ungeprüften File-Handle verwenden.

WICHTIG ist nur, DASS der File-Handle auf seine gültigkeit geprüft wird BEVOR man in verwendet.

MfG Peter(TOO)

Moin,

Frage, warum soll bei der obigen (leichter verständlicheren)
Variante die Prüfung „zu spät erfolgen?“.

Beide Varianten resultieren meiner Meinung nach in exakt dem
selben Ergebnis!

Es geht nicht nur um das Ergebnis. Man sollte sich auch angewöhnen, so zu programmieren, daß der Code gut verständlich ist.
Im konkreten Fall (eigentlich fast immer) macht es Sinn, wenn man unmittelbar nach dem fopen() prüft, ob der Vorgang erfolgreich war. Das kann, muß aber nicht mit der ((file = fopen()) == NULL)-Konstruktion erfolgen.

Thorsten

Moin,

Ich muss dir hier etwas wiedersprechen; ein guter Compiler
wird in beiden Fällen genau den gleichen Code erzeugen !

Na und? Es geht doch nicht nur um Laufzeitoptimierung.

WICHTIG ist nur, DASS der File-Handle auf seine gültigkeit
geprüft wird BEVOR man in verwendet.

Das kann man auch gleich erledigen.

Thorsten