Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Binär -> C++ -> Hex -> Binär

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
27.08.2007, 01:26 Uhr
~Sorrow
Gast


Hallo,
ich möchte hier mal ein kleines Vorhaben erläutern und ein paar Meinungen einholen.

Ziel ist es eine binäre Datei einzulesen, sie intern in das Hex-Format zu konvertieren und damit Such-, Zähl- Vergleich- und Rechenoperationen vorzunehmen.
Z.B. Zählung einer vorkommenden Bytefolge, Abstand solcher Bytefolgen etc.
Entfernen und Hinzufügen, bzw. ersetzen von Bytefolgen gehören ebenso dazu.
Die Hexzahlen mussen so verfügbar sein, als würde ich sie mit einem Hex-Editor öffnen.
Am Ende soll(en) das/die hex-arrays wieder binär gepeichert werden.
Die einzulesenden Dateien sind >4GB, können sogar bis 20GB groß sein.

Wie kann man sowas am Besten realisieren?
Da die Dateien >4GB sind, muss man sicher nen Puffer oder etwas in der Art verwenden.
Was für Methoden gibt es gerade für das Einlesen und Abspeichern?
Kann man evtl. direkt mit einem Befehl als Hex einlesen oder muss ich jedes Zeichen als ASCII einlesen und in eine Hexadezimalzahl konvertieren?
Wenn ja, wie gehe ich am Besten vor um hohe Geschwindigkeiten für den Einlesevorgang und Ausgabevorgang zu erreichen.

Ich bin kein C++ Profi, sondern hatte mal 2 Semester im Studium, also bitte ich um ein wenig Nachsicht. Gerne nehme ich auch weitere Hinweise und Kritikpunkte an.

Vielen Dank
Sorrow
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
27.08.2007, 02:22 Uhr
Hans
Library Walker
(Operator)


Hi,

Zitat von Sorrow:

Ziel ist es eine binäre Datei einzulesen, sie intern in das Hex-Format zu konvertieren und damit Such-, Zähl- Vergleich- und Rechenoperationen vorzunehmen.
...
Die Hexzahlen mussen so verfügbar sein, als würde ich sie mit einem Hex-Editor öffnen.


wenn Du eine Datei binär einliesst, ist keine weitere Konvertierung nötig. Die Art und Weise, wie auch ein HEX-Editor die Daten darstellt, dient doch nur der Übersicht. Wenn Du mit einem Programm die Bits von irgendwelchen Daten veränderst, ist es egal, ob die Änderungsanweisungen dezimal, dual oder hex angegeben ist. Beispiel:

C++:
int a, b;

a = 1;
b = a | 64;    /* Änderungsangabe dezimal */
printf ("%d", b);

b = a | 0100;    /* Änderungsangabe oktal */
printf ("%d", b);

b = a | 0x40;    /* Änderungsangabe hex */
printf ("%d", b);


Hier hab ich von der Variablen a jedesmal das Bit 7 gesetzt und das Ergebniss in b gespeichert. Das Format, in dem ich angegeben habe, dass das Bit 7 zu setzen ist, ist zwar jedes mal anders, das Ergebniss ist aber immer gleich.

Was die Dateigrösse angeht, so ist es sicherlich Sinnvoll, mit Puffern zu arbeiten. Aber das ist nicht trivial, und bedarf schon einer genaueren Planung, wie es von statten gehen soll.
Zuerst einmal musst Du die Datei als binäre Datei öffnen, und dann am besten Blockweise einlesen. Je nach dem wie gross Dein Puffer ist, liesst Du so viele Blöcke, wie in den Puffer passen, und arbeitest damit. Wenn Du mit der Bearbeitung fertig bist, schreibst Du den Pufferinhalt erst mal wieder in eine andere Datei, und liesst den nächsten Teil. Dabei muss sich dein Programm merken, wieviele Blöcke es gelesen hat, damit es später an der richtigen Stelle in der Datei weiter liesst.
Diese Vorgehensweise ist aber nur dazu geeignet eine Datei einmal von Anfang bis Ende zu bearbeiten. Wenn sich bei der Bearbeitung irgendwo in der Mitte heraus stellt, das auch wieder Teile bearbeitet werden müssen, die weiter vorne oder weiter hinten in der Datei liegen, muss man sich was anderes überlegen. Und damit wird es kompliziert...

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
28.08.2007, 23:29 Uhr
~Sorrow
Gast


Vielen Dank schonmal für die Antwort.
Irgendwie bin ich mit dem von dir geposteten Beispiel nicht zurecht gekommen.
Wie auch immer.
Ich habe mir jetzt folgendes zusammengetippt:


C++:
int main()
{
    int c;

    FILE *In = fopen("datei.abc", "r");
    FILE *Out = fopen("hex.txt", "a");

    while (!feof(In)) {
        c = fgetc(In);
        if (c<16) {fprintf(Out, "%x", 0);}
        fprintf(Out, "%x", c);
    }

    fclose(Out);
    fclose(In);

    return 0;
}



Dieser Teil liest eine X-beliebige Datei ein und speichert den Inhalt als Hex-Werte in der Datei hex.txt. Das ist nur zum Testen, später soll das intern in ein array geleitet werden.

Das funktioniert eigentlich soweit ganz gut, allerdings liest das Programm eine Datei nicht komplett ein, sondern bricht irgendwann mittendrin ab.
Ich kann mir leider nicht erklären, warum.
Könnte mir da evtl. jemand nen Hinweis geben?

Danke
Sorrow
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
29.08.2007, 00:26 Uhr
Kest
saint


Hi!

Versuch mal:

C++:
FILE *In = fopen("datei.abc", "rb");


--
Wenn man einen Hufschlag hört, sollte man >Pferd< denken und nicht >Zebra<.

Dieser Post wurde am 29.08.2007 um 00:27 Uhr von Kest editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
29.08.2007, 01:11 Uhr
~Sorrow
Gast


Das wars!

greets
Sorrow
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
29.08.2007, 13:34 Uhr
Hans
Library Walker
(Operator)



Zitat von ~Sorrow:
Vielen Dank schonmal für die Antwort.
Irgendwie bin ich mit dem von dir geposteten Beispiel nicht zurecht gekommen.


Hi,
das ist ja auch kein vollständiges Programm, sondern nur der Teil Programmcode, der nötig ist, um den Sachverhalt zu verdeutlichen, um den es in der Erklärung geht. Als vollständiges Programm muss das so aussehen:

C++:
#include <stdio.h>

int main ()
{
   int a, b;

   a = 1;
   b = a | 64;    /* Änderungsangabe dezimal */
   printf ("%d\n", b);

   b = a | 0100;    /* Änderungsangabe oktal */
   printf ("%d\n", b);

   b = a | 0x40;    /* Änderungsangabe hex */
   printf ("%d\n", b);

   return 0;
}


Nebenbei: das ist C, kein C++, auch wenn es oben drüber steht.



Zitat:

Ich habe mir jetzt folgendes zusammengetippt:


C++:
int main()
{
    int c;

    FILE *In = fopen("datei.abc", "r");
    FILE *Out = fopen("hex.txt", "a");

    while (!feof(In)) {
        c = fgetc(In);
        if (c<16) {fprintf(Out, "%x", 0);}
        fprintf(Out, "%x", c);
    }

    fclose(Out);
    fclose(In);

    return 0;
}



Dieser Teil liest eine X-beliebige Datei ein und speichert den Inhalt als Hex-Werte in der Datei hex.txt. Das ist nur zum Testen, später soll das intern in ein array geleitet werden.

Das funktioniert eigentlich soweit ganz gut, allerdings liest das Programm eine Datei nicht komplett ein, sondern bricht irgendwann mittendrin ab.
Ich kann mir leider nicht erklären, warum.
Könnte mir da evtl. jemand nen Hinweis geben?

Danke
Sorrow

Jo, das sieht schon mal ganz gut aus, hat aber 3 Haken.
Der Erste ist der, das es keine X-beliebige Datei ist, sondern die Datei mit dem Namen: "datei.abc".
Der zweite Haken ist, dass es nur mit Textdateien klappt. Sobald andere Zeichen (wiez.B. Steuerzeichen) drin stehen wird es Probleme geben. Der Grund dafür ist der, das Du bei fopen nicht angibst, das die Datei binär zu öffnen ist. Dazu muss hinter dem r für read noch ein b für binary. Also:
*In = fopen("datei.abc", "rb");
Wenn Du das "b" weg lässt, geht fopen davon aus, das es sich um eine Textdatei handelt.
Der dritte Haken ist das eof. Eof steht zwar für End Of File, gilt aber meisst nur bei Textdateien. Sobald andere Daten (z.B. Multimedia) ins Spiel kommen, kommst Du damit nicht mehr weiter. Aber das hast Du ja auch schon gemerkt, denn mit dieser Zeile:

C++:
if (c<16) {fprintf(Out, "%x", 0);}


veränderst Du ja auch schon den Inhalt der gelesenen Datei, indem Du alle Bytes, die kleiner als 16 sind durch Nullen ersetzt.

Du kannst Dir die Länge einer Datei aber auch vom Betriebssystem geben lassen, und damit arbeiten. Das ist die bessere Lösung, weil Du Dir das EOF dann sparen kannst.

Ich schick Dir hier mal ein Beispielprogramm zur Dateibearbeitung, das ich mir vor längerer Zeit mal gebastelt habe. Ich hatte das Problem, das mein Webbrowser beim abspeichern von HTML-Dateien aus einem mir unerfindlichen Grund immer noch ein zusätzliches Carrige Return (CR) in die Dateien geschrieben hat. Das Ergebniss war eine zusätzliche Leerzeile, die beim späteren lesen einfach nur lästig war...
Und weil die Dateien immer unterschiedlich lang sind, und man die Länge im voraus nicht wissen kann, habe darin auch Blockweise gearbeitet, wie ich es in meinem ersten Posting schon mal beschrieben habe. Aber hier erst mal der ausführlich kommentierte Programmtext:

C++:
/* Datei: CR-change.c

   Programm zum überschreiben von doppelten CR-Zeichen in HTML-Dateien.
   Es wird nach dem auftreten der Zeichenfolge CR CR LF ( 0d 0d 0a hex.)
   gesucht, und darin das erste CR durch ein Leerzeichen ersetzt.

   Version 1.1 by HGP

   Vorgehensweise:
      * (Quell-)Datei öffnen
      * getftime() ausführen, und Ergebnisse merken
      * Datei bearbeiten, d.h. neue Datei mit gewünschtem Inhalt erstellen
      * Quelldatei einen neuen Namen verpassen: *.bak, oder sowas...
      * neuer Datei den Namen der alten zuweisen, oder den vom Benutzer
         vorgegebenen
      * setftime() aufrufen, womit der eben erstellten Datei das Datum und
         die Zeit der Quelldatei zugewiesen wird.
      * Alle Dateien schliessen, und Ende

*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>


int main(int argc, char *argv[])
{
  FILE *in, *out;
  struct ftime filetime; // Zeit und Datumsinformationen

  int bl, l, handle;
  char flag=0,     // Zeigt an, ob ein geprüftes Zeichen ein CR
       infilename[30],  // war (dann != 0)
     outfilename[30], // Speicher der Dateinamen
     *wbuf;    // Zeiger auf den Bereich, wo der zu bearbeitende
               // Text steht

  switch (argc)
    {
      case 1:
      /* Wenn keine Parameter angegeben wurden */
        printf ("\nAufruf: CR-change <Name der Eingabedatei>"\
                 "[<Name der Ausgabedatei>]\n");
        exit (1);
        break;

      case 2:
      /* Nur ein Parameter angegeben
         -> Ausgabedatei erhält am Ende den Namen der Eingabedatei

       * zunächst den Namen der EingabeDatei in den Namen der
          Ausgabedatei kopieren
       * Dann die Namenserweiterung der Ausgabedatei merken, und
          aus dem namen der Ausgabedatei killen.
       * Datei mit diesem Namen öffnen und
       * bearbeiten
      */

        strcpy (infilename, argv[1]);
        strcpy (outfilename, infilename);
          l=strlen(outfilename);
          while(l)
              { if (outfilename[l] != '.')
              l--;
              }
        outfilename[l] = '\0';
        break;

      case 3: /* Zwei Parameter angegeben
              -> Für Ein- und Ausgabedatei sind separate Namen
                   angegeben */

        strcpy (infilename, argv[1]);
        strcpy (outfilename, argv[2]);
        break;

      default:
              ;  /* nichts tun */
    } /* switch() */

  if ((in=fopen(infilename, "rb")) == NULL)
     {
       fprintf(stderr, "Can't open input file: %s\n", infilename);
       exit(1);
     }

  if ((out=fopen(outfilename, "wb")) == NULL)
     {
       fprintf(stderr, "Can't open output file: %s\n", outfilename);
       exit(1);
     }

   /* das mit dem eingabeStream verbundene Dateihandle holen */
   handle = fileno(in);

   /* Zeit und Datum der eingabeDatei holen */
   getftime(handle, &filetime);

  /* Hier die Bearbeitung... - Eine einfache kopier-Schleife geht nicht,
     da zwei aufeinander folgende Zeichen überprüft werden müssen, von
     denen das erste ersetzt werden soll, wenn die Bedingung zutrift.
     -> Die Datei ist Blockweise in den Speicher zu holen, zu bearbeiten,
         wieder abzuspeichern.  */


  /* Speicherplatz reservieren */
  if ((wbuf = malloc(1024 * sizeof(char))) == NULL)
     {
       printf("Nicht genügend Speicher\n");
       exit(1);   /* Beendet das Programm, wenn kein Speicher mehr */
     }            /* vorhanden ist */


  /* im Speicher befindlichen Teil überprüfen */
   while ((bl = fread(wbuf, sizeof(char), 1024, in)) > 0)
     {                            // 1024 Byte aus der Eingabedatei lesen
       for (l=0; l<=bl; l++)
         { if (*(wbuf+l) == 0x0d) flag=1;      // Wenn Zeichen ein CR, dann
                                              // flag setzen
           if (flag && (*(wbuf+l+1) == 0x0d)) // Nachfolgendes Zeichen auch
                                                // ein CR ?
              *(wbuf+l) = ' ';         // dann aus aktuellem Zeichen ein Blank
                                   // machen
           flag=0;                // flag löschen, da keine CRs mehr
                                //hintereinander
         } /* for-Schleife */
       fwrite (wbuf, sizeof(char), bl, out);    // Änderungen speichern
     } /* while-Schleife */


  /* das mit dem ausgabeStream verbundene Dateihandle holen */
  handle = fileno(out);

  /* Zeit und Datum der AusgabeDatei auf die Werte der Eingabedatei
      setzen */

  setftime(handle, &filetime);

  /* Alle Dateien schliessen */
  fclose (in);
  fclose (out);

  /* Dateien umtaufen
     Hier muss erst geprüft werden, ob ein Name für die Ausgabedatei
     angegeben wurde. Wenn ja,
         dann wird nichts umbenannt, sondern das Programm beendet.
     Wenn nicht,
       * dann wird die Namenserweiterung der Eingabedatei so ersetzt, das
         sie als Backup kennzeichnet, umbenannt.
       * Der erzeugten Datei die Erweiterung der Eingabedatei geben, und
       * ebenfalls umbenennen
  */

  if (argc == 2) // Es wurde nur ein Dateiname angegeben
    {
      l=0;
      while(infilename[l] != '.' || infilename[l] != '\0')
        {
          wbuf[l]=infilename[l];
          l++;
        }
      strcpy(wbuf+l, "old");
      rename(infilename, wbuf);

      // strcpy(wbuf, infilename);
      rename(outfilename, infilename);
    }

  /* Verwendeten Speicher wieder frei geben */
  free (wbuf);

  return 0;
} /* main */



Dazu ist noch folgendes anzumerken:
Das Programm enthält ein paar Funktionsaufrufe, die möglicherweise Borlandspezifisch sind, d.h. nur von einem Borlandcompiler verarbeitet werden. Wenn Du mit einem Borlandcompiler arbeitest, braucht Dich das nicht weiter zu kümmern. Wenn der Compiler meckert, dann must Du wahrscheinlich folgendes streichen:
* Die Zeile #include <io.h>
* Alle Zeilen, wo irgendwas mit "ftime" drin steht, also getftime() und setftime()
* alle Zeilen, in denen die Funktion fileno() aufgerufen wird.

Soweit erst mal das.
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 29.08.2007 um 13:52 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
29.08.2007, 13:40 Uhr
Hans
Library Walker
(Operator)


Und hier der zweite Teil, weil es zu lang war, um es an einem Stück zu verschicken...

Wenn Du das Programm komplett verstanden hast, bist Du schon ein grosses Stück weiter. Um es zu testen hier mal eine HTML-Datei in einer Art Hexdump, die ich mit einer leicht modifizierten Version von Deinem Programm erzeugt habe:

Code:
0000  3c 68 74 6d 6c 3e 0d 0a 3c 74 69 74 6c 65 3e 0d
0010  0a 20 42 6c 26 6f 75 6d 6c 3b 64 20 64 61 72 67
0020  65 73 74 65 6c 6c 74 65 72 20 54 65 78 74 2e 2e
0030  2e 20 0d 0a 3c 2f 74 69 74 6c 65 3e 0d 0a 0d 0a
0040  3c 62 6f 64 79 20 62 67 63 6f 6c 6f 72 3d 77 68
0050  69 74 65 3e 0d 0a 3c 68 31 3e 0d 0a 26 6e 62 73
0060  70 3b 20 20 42 6c 26 6f 75 6d 6c 3b 64 20 64 61
0070  72 67 65 73 74 65 6c 6c 74 65 72 20 54 65 78 74
0080  3c 62 72 3e 0d 0a 3c 2f 68 31 3e 0d 0a 3c 70 72
0090  65 3e 0d 0a 44 69 65 73 20 68 69 65 72 20 69 73
00A0  74 20 6d 61 6c 20 73 6f 20 65 69 6e 20 62 6c 26
00B0  6f 75 6d 6c 3b 64 65 20 64 61 72 67 65 73 74 65
00C0  6c 6c 65 74 65 72 20 54 65 78 74 2c 20 66 fc 72
00D0  20 0d 0d 0a 64 65 6e 20 69 63 68 20 64 61 73 20
00E0  50 72 6f 67 72 61 6d 6d 20 43 52 2d 63 68 61 6e
00F0  67 65 20 65 69 6e 6d 61 6c 20 67 65 73 63 68 72
0100  69 65 62 65 6e 20 68 61 62 65 2e 20 0d 0d 0a 44
0110  61 73 20 6d 61 67 20 62 65 69 20 64 69 65 73 65
0120  6d 20 6b 75 72 7a 65 6e 20 54 65 78 74 20 7a 77
0130  61 72 20 6e 69 63 68 74 20 64 72 61 6d 61 74 69
0140  73 63 68 20 73 65 69 6e 2c 20 0d 0d 0a 61 62 65
0150  72 20 77 65 6e 6e 20 64 69 65 20 54 65 78 74 20
0160  6c 26 61 75 6d 6c 3b 6e 67 65 72 20 77 65 72 64
0170  65 6e 2c 20 64 61 6e 6e 20 73 63 68 6f 6e 2e 20
0180  41 75 73 73 65 72 64 65 6e 20 0d 0d 0a 77 61 72
0190  65 6e 20 73 69 65 20 20 6a 61 20 76 6f 72 68 65
01A0  72 20 61 75 63 68 20 61 6e 64 65 72 73 20 66 6f
01B0  72 6d 61 74 69 65 72 74 2c 20 64 2e 68 2e 20 64
01C0  69 65 20 0d 0d 0a 7a 75 73 26 61 75 6d 6c 3b 74
01D0  7a 6c 69 63 68 65 20 4c 65 65 72 7a 65 69 6c 65
01E0  20 66 65 68 6c 74 65 2e 0d 0a 3c 2f 70 72 65 3e
01F0  0d 0a 26 55 75 6d 6c 3b 62 72 69 67 65 6e 73 20
0200  73 63 68 65 69 6e 74 20 65 73 20 64 61 73 20 50
0210  72 6f 62 6c 65 6d 20 62 65 69 20 61 6b 74 75 65
0220  6c 6c 65 6e 20 57 65 62 62 72 6f 77 73 65 72 6e
0230  3c 62 72 3e 20 0d 0a 61 75 63 68 20 6e 69 63 68
0240  74 20 6d 65 68 72 20 7a 75 20 67 65 62 65 6e 2e
0250  2e 2e 20 3b 2d 29 0d 0a 3c 2f 62 6f 64 79 3e 0d
0260  0a 3c 2f 68 74 6d 6c 3e 0d 0a


Hier noch das modifizierte Programm:

C++:
#include <stdio.h>

int main()
{
    int c, i;

    FILE *In, *Out;

    In = fopen("bsp.htm", "rb");
    Out = fopen("bsp.dmp", "ab");

    i = 0;
    while (!feof(In))
    {
        if ((i%16)==0)
            fprintf(Out, "\n%04X  ", i);
                
        c = fgetc(In);
        if (c== -1)     /* Prüfe, ob c=EOF ist; */
            break;     /* EOF entspricht meisst dem Wert -1 */    
        /* if (c<16) {fprintf(Out, "%02x ", 0);} */
        fprintf(Out, "%02x ", c);
        i++;
    }

    fclose(Out);
    fclose(In);

    return 0;
}



Und nun frohes schaffen.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 29.08.2007 um 13:56 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
29.08.2007, 17:50 Uhr
0xdeadbeef
Gott
(Operator)


Ich hab da mal in der alten Trickkiste gewühlt

C++:
char b[17];int c,f,i,j;main(k,s)int**s;{for(f=--k*open(*++s,0);(k=read(f,&c,1))+j;(j%=16)
||puts(b))j||printf("%07x0 ",i++),printf(k?"%02x ":"   ",c),b[j++]=k?isprint(c)?c:46:0;}


Bzw. in lesbar:

C++:
#include <ctype.h>
#include <stdio.h>

#define LINE_MAX 16

int main(int argc, char *argv[]) {
  char buf[LINE_MAX];
  int i, lineend;

  FILE *in  = stdin,
       *out = stdout;

  if(argc > 1) in  = fopen(argv[1], "rb");
  if(argc > 2) out = fopen(argv[2], "w" );

  if(!in || !out) {
    fputs("Fehler beim Öffnen der Dateien", stderr);
    return -1;
  }

  for(i = 0; lineend = fread(buf, sizeof(char), LINE_MAX, in); i += LINE_MAX) {
    int j;

    fprintf(out, "%#08x ", i);
    for(j = 0; j < lineend; ++j) {
      fprintf(out, "%02x ", buf[j]);
    }
    for(j = lineend; j < LINE_MAX; ++j) {
      fputs("   ", out);
    }
    for(j = 0; j < lineend; ++j) {
      fputc(isprint(buf[j]) ? buf[j] : '.', out);
    }
    fputc('\n', out);
  }

  return 0;
}


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 29.08.2007 um 17:52 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
29.08.2007, 22:47 Uhr
~Sorrow
Gast


Jetzt gehts ja richtig los hier.


Zitat:
...um den Sachverhalt zu verdeutlichen, um den es in der Erklärung geht...

Den ich jetzt auch verstanden habe. "%02x" fügt genau die "0" ein, die ich vermisst und mit der Zeile

C++:
if (c<16) {fprintf(Out, "%x", 0);

hinzugefügt hatte.


Zitat:
Der Erste ist der, das es keine X-beliebige Datei ist, sondern die Datei mit dem Namen: "datei.abc".

Das ist schon klar, das war ja nur zum Testen, ich kann dafür ja jede x-beliebige Datei zu "datei.abc" umbenennen. Wird natürlich alles später mit argv/argc realisiert.


Zitat:
Der zweite Haken ist, dass es nur mit Textdateien klappt. Sobald andere Zeichen (wiez.B. Steuerzeichen) drin stehen wird es Probleme geben. Der Grund dafür ist der, das Du bei fopen nicht angibst, das die Datei binär zu öffnen ist. Dazu muss hinter dem r für read noch ein b für binary. Also:
*In = fopen("datei.abc", "rb");

Genau, das hab ich nun auch kapiert. Hatte Kest ja auch schon erwähnt.
Direkt schonmal die nächste Frage dazu.
Wenn ich diese Hexdatei später zum parsen usw. weiterverarbeite lasse ich das "b" fürs Lesen weg und die Datei wird dann im Textmodus geöffnet, so dass ich dann mit den Hex-Werten arbeiten kann.
Wenn ich die veränderten Hex-Daten dann wieder abspeichern will, soll das natürlich wieder binär werden. Kann ich dann beim Schreiben des Out-Files einfach "wb" angeben und ich erhalte dann wieder automatisch ein Binärfile?


Zitat:
Der dritte Haken ist das eof. Eof steht zwar für End Of File, gilt aber meisst nur bei Textdateien. Sobald andere Daten (z.B. Multimedia) ins Spiel kommen, kommst Du damit nicht mehr weiter.

Hier muss ich nochmal einhaken:
Warum wird in der while-schleife bei deiner Modifizierung denn nochmal EOF abgefragt?
Wenn EOF für Textfiles ist brauche ich das doch nicht, da ich doch binär einlese. Außerdem soll wie ich hier im Abschnitt zu "fgetc" las, beim Einlesen von Binärdateien "feof" benutzen, damit das Ende eines Files sicher erkannt wird, und das wird ja schon in der Bedingung der while-Schleife abgefragt.

Das andere Programm werde ich mir mal in Ruhe anschauen und das von 0xdeadbeef auch.
Danke für eure Unterstützung.

------------------

Allerdings sehe ich schon einen Haufen neue Probleme kommen *argh*.
Die Hex-Datei wird ~3x so groß wie die Quelldatei. Bei nem 20GB File ist das riesig und die Weiterverarbeitung braucht ja evtl. auch nochmal so viel Platz. Ich glaube ich werde da irgendwie Abschnittsweise arbeiten müssen.

------------------

Wenn ich schonmal dabei bin:

Zitat:
Du kannst Dir die Länge einer Datei aber auch vom Betriebssystem geben lassen, und damit arbeiten. Das ist die bessere Lösung, weil Du Dir das EOF dann sparen kannst.

Ich hatte mir eine Funktion geschrieben, die mir die Dateigröße ausgibt und damit eine Fortschrittsanzeige realisiert (Mittels Zeigerposition auf das Anfang und Ende des Files und den Funktionen "fseek() / ftell()" ). Das klappt auch ganz hervorragend, allerdings nicht mehr bei Dateien, deren Größe in Byte die Kapazität der Standarddatentypen sprengt. "unsigned int" wäre ja das Maximum, aber das reicht nicht.
Wie also lässt man sich denn die Größe vom System geben?

greets
Sorrow
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
30.08.2007, 03:17 Uhr
Hans
Library Walker
(Operator)


Hi,

ich fang mal hinten an...
unsigned int ist bei einem 32-Bit Compiler auch 32 Bit breit, d.h. der größte Wert ist 2 hoch 32, was genau 4 GB entspricht. Wenn Dein Compiler den C99-Standard unterstützt, dann stellt er den Datentyp long long zur Verfügung, der 64 Bit breit ist.
Oder, wenn Du unter einem 64 Bit Betriebssystem arbeitest und das Programm als 64 Bit Applikation übersetzt, kann es auch sein, das die int-Variablen 64 Bit breit sind. Dazu kann ich aber nichts genaues sagen, weil ich kein 64-Bit System habe. D.h. Du musst es ausprobieren. Irgendwo hier im Forum, wahrscheinlich in den FAQs, gibt es ein entsprechendes Programm, das die breite der Datentypen liefert. Wenn du einen 64 Bit breiten int zur Verfügung hast, kannst Du damit Zahlen von 0 bis 1.84467e19 darstellen, womit auch für 20 bis 60 GB große Dateien genug Platz zur Verfügung steht.
Wenn kein 64 Bit Typ verfügbar ist, musst Du in der Tat Blockweise arbeiten, so ähnlich, wie ich es oben schon mal beschrieben habe.

Die Frage, warum ich auch in dem geänderten Programm noch EOF abfrage, lässt sich ganz einfach beantworten: Zum einen wollte ich von Deinem Programm nicht zu viel ändern, damit Du Deine Überlegungen auch noch darin wiederfinden kannst, zum anderen habe ich da keinen Funktionsaufruf drin, der mir die Dateilänge vom Betriebssystem liefern würde. - Aber am Dateiende soll die Schleife ja abgebrochen werden. Also brauche ich die EOF-Abfrage noch.

Und warum ich EOF in der Schleife noch mal abfrage wird Dir am besten klar, wenn Du die Abfrage mal heraus nimmst, und Dir die Ausgabe dann ansiehst.

Ein weiteres Beispiel für die Verwendung der Kommandozeilenparameter mittels argc/argv hast Du u.a. in dem langen Programm, das ich hier gepostet habe, oder auch in dem von 0xdeadbeef.

Und jetzt noch mal zur Bearbeitung der Daten im Rechner...
Wir nehmen einfach mal diesen breitgrinsenden Smiley hier und speichern ihn lokal ab. (Ich hoffe wir kriegen deshalb keine Probleme von wegen Copyright.) Das ergibt bei mir eine 245 Byte grosse Gif-Datei. Da Gif ein komprimiertes Format ist, ich aber gerne unkomprimierte Daten hätte, hab das Bild mit IrfanView (Version 3.97) geladen, und als Windows-BMP Datei wieder gespeichert. Diese Datei wurde bei mir 1318 Byte gross. Eine Betrachtung der Datei mit einem Hexeditor offenbart, dass sie in der Mitte einen 896 (hex.: 380) Byte grossen Block aus Nullen enthält. Aus einigen dieser Nullen hab ich mit dem folgenden Spezialprogramm Einsen gemacht, wie sich per Hexeditor leicht nachprüfen lässt.

C++:
/* Datei: bitchg.c

   Programm zum ändern von Bytes in Dateien.

   Version 1.0 by HGP
*/


#include <stdio.h>
#include <stdlib.h>

long int filesize( FILE *fp );

int main(int argc, char *argv[])
{
  FILE *in, *out;

  long int bl, l;
  char *wbuf;       // Zeiger auf den Bereich, wo die zu bearbeitenden Daten stehen

  if ((in=fopen(argv[1], "rb")) == NULL)
     {
       fprintf(stderr, "Kann Eingabedatei nicht öffnen: %s\n", argv[1]);
       exit(1);
     }

  if ((out=fopen(argv[2], "wb")) == NULL)
     {
       fprintf(stderr, "Kann Ausgabedatei nicht öffnen: %s\n", argv[2]);
       exit(1);
     }

  l = filesize(in);     // Dateilänge ermitteln

  /* 4 KB Speicherplatz reservieren */
  if ((wbuf = malloc(4096 * sizeof(char))) == NULL)
     {
       printf("Nicht genügend Speicher\n");
       exit(1);   /* Beendet das Programm, wenn kein Speicher mehr */
     }            /* vorhanden ist */

  bl=0;
  /* Datei in den Speicher holen */
  while (bl<l)
    {  
       *(wbuf+bl) = fgetc(in);
       bl++;
    }      
  
  /* Daten ändern... */
  for (bl=0xc0; bl<0x400; bl++)
      *(wbuf+bl) = 1;

  bl=0;
  /* Datei schreiben */
  while (bl<l)
    {  
       fputc( *(wbuf+bl), out);
       bl++;
    }      
  
  /* Verwendeten Speicher wieder frei geben */
  free (wbuf);

  /* Alle Dateien schliessen */
  fclose (in);
  fclose (out);

  return 0;
} /* main */


/* Diese Funktion zum ermitteln der Grösse einer Datei stammt aus den
   Beispieldateien des OpenWatcom C/C++ Compilerpakets.
*/

long int filesize( FILE *fp )
{
    long int save_pos, size_of_file;

    save_pos = ftell( fp );
    fseek( fp, 0L, SEEK_END );
    size_of_file = ftell( fp );
    fseek( fp, save_pos, SEEK_SET );
    return( size_of_file );
}


Die Preisfrage ist jetzt: Wo hab ich da die Umwandlung, bzw. Ausgabe als Hexdump drin?
(Die Antwort steht schon oben in meinem ersten Posting.)

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 30.08.2007 um 03:39 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: