Lesen der gesamten Textdatei in ein Char-Array in C

Lesezeit: 8 Minuten

Benutzeravatar von friedkiwi
Friedkiwi

Ich möchte den Inhalt einer Textdatei in ein Char-Array in C einlesen. Zeilenumbrüche müssen beibehalten werden.

Wie mache ich das? Ich habe einige C++-Lösungen im Web gefunden, aber keine reine C-Lösung.

Edit: Ich habe jetzt folgenden Code:

void *loadfile(char *file, int *size)
{
    FILE *fp;
    long lSize;
    char *buffer;

    fp = fopen ( file , "rb" );
    if( !fp ) perror(file),exit(1);

    fseek( fp , 0L , SEEK_END);
    lSize = ftell( fp );
    rewind( fp );

    /* allocate memory for entire content */
    buffer = calloc( 1, lSize+1 );
    if( !buffer ) fclose(fp),fputs("memory alloc fails",stderr),exit(1);

    /* copy the file into the buffer */
    if( 1!=fread( buffer , lSize, 1 , fp) )
      fclose(fp),free(buffer),fputs("entire read fails",stderr),exit(1);

    /* do your work here, buffer is a string contains the whole text */
    size = (int *)lSize;
    fclose(fp);
    return buffer;
}

Ich bekomme eine Warnung: Warnung: Zuweisung macht Zeiger aus Ganzzahl ohne Umwandlung. Das steht auf dem Spiel size = (int)lSize;. Wenn ich die App starte, kommt es zu Segfaults.

Aktualisieren: Der obige Code funktioniert jetzt. Ich habe den Segfault gefunden und eine weitere Frage gestellt. Danke für die Hilfe.

  • Mögliches Duplikat von Easiest way to get file’s content in C

    – Ciro Santilli OurBigBook.com

    29. Oktober 2015 um 12:49 Uhr

  • Die Verwendung von fseek() zum Abrufen der Dateigröße beschränkt Sie darauf, nur echte Festplattendateien zu lesen. Wenn Sie es verwenden, können Sie nicht aus einer Pipe (wie der Standardeingabe), benannten Pipes, Geräten oder Netzwerkstreams lesen. Siehe den Link im obigen Kommentar. Der einfachste Weg, um den Inhalt der Datei in C abzurufen

    – Antonius

    5. Januar 2017 um 5:06 Uhr

  • Bitte bearbeiten Sie keine Antworten in Fragen. Posten Sie Ihre eigene Antwort, wenn Sie eine ausgefeilte Version davon wünschen. Dies hat Fehler wie size = (int *)lSize; das setzt die lokale Zeigervariable size in eine Ganzzahl, die in einen Zeiger umgewandelt wird, tut aber nichts, um die zu aktualisieren int der Aufrufer übergab einen Zeiger auf. (Wahrscheinlich meintest du *size = lSize). Diese fehlerhafte Antwort sollte also abgelehnt werden, aber sie steht in der Frage, die eine vernünftige Frage ist. Sie erwähnen auch, dass Sie einen Segfault gefunden (und behoben?) haben, aber ist dies der alte Code oder der feste Code? Wie auch immer, sollte nicht im Q sein, auch wenn es in Ordnung war, es zu kopieren/einzufügen

    – Peter Cordes

    15. Oktober 2021 um 10:43 Uhr


FILE *fp;
long lSize;
char *buffer;

fp = fopen ( "blah.txt" , "rb" );
if( !fp ) perror("blah.txt"),exit(1);

fseek( fp , 0L , SEEK_END);
lSize = ftell( fp );
rewind( fp );

/* allocate memory for entire content */
buffer = calloc( 1, lSize+1 );
if( !buffer ) fclose(fp),fputs("memory alloc fails",stderr),exit(1);

/* copy the file into the buffer */
if( 1!=fread( buffer , lSize, 1 , fp) )
  fclose(fp),free(buffer),fputs("entire read fails",stderr),exit(1);

/* do your work here, buffer is a string contains the whole text */

fclose(fp);
free(buffer);

  • Sie können die Datei schließen, bevor Sie an den Daten arbeiten, anstatt danach.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    19. September 2010 um 19:40 Uhr

  • Irgendein besonderer Grund für calloc über malloc?

    – Tanaki

    30. September 2013 um 16:22 Uhr

  • @Tanaki Normalerweise nenne ich C-Strings als redundanten Sicherheitsmechanismus, nur für den Fall, dass der C-String, der in den Puffer gestellt wird, aus irgendeinem Grund nicht NUL-terminiert ist. In den meisten Standardfällen ist dies jedoch wahrscheinlich eine unnötige Vorsichtsmaßnahme.

    – Ephemera

    3. Oktober 2013 um 3:34 Uhr

  • @ephemera: fread befasst sich mit Rohdaten und macht sich nicht die Mühe, einen Nullterminator einzufügen. Verwenden calloc zwingt Ihren Code auch dazu, den Puffer einmal mehr als nötig zu durchlaufen.

    – diapir

    23. November 2013 um 3:49 Uhr

Emmets Benutzeravatar
Emmet

Eine Lösung in Form eines vollständigen Programms, das die Frage beantwortet und demonstriert. Es ist etwas expliziter als andere Antworten und daher für weniger erfahrene Personen leichter verständlich C (MEINER BESCHEIDENEN MEINUNG NACH).

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

/*
 * 'slurp' reads the file identified by 'path' into a character buffer
 * pointed at by 'buf', optionally adding a terminating NUL if
 * 'add_nul' is true. On success, the size of the file is returned; on
 * failure, -1 is returned and ERRNO is set by the underlying system
 * or library call that failed.
 *
 * WARNING: 'slurp' malloc()s memory to '*buf' which must be freed by
 * the caller.
 */
long slurp(char const* path, char **buf, bool add_nul)
{
    FILE  *fp;
    size_t fsz;
    long   off_end;
    int    rc;

    /* Open the file */
    fp = fopen(path, "rb");
    if( NULL == fp ) {
        return -1L;
    }

    /* Seek to the end of the file */
    rc = fseek(fp, 0L, SEEK_END);
    if( 0 != rc ) {
        return -1L;
    }

    /* Byte offset to the end of the file (size) */
    if( 0 > (off_end = ftell(fp)) ) {
        return -1L;
    }
    fsz = (size_t)off_end;

    /* Allocate a buffer to hold the whole file */
    *buf = malloc( fsz+(int)add_nul );
    if( NULL == *buf ) {
        return -1L;
    }

    /* Rewind file pointer to start of file */
    rewind(fp);

    /* Slurp file into buffer */
    if( fsz != fread(*buf, 1, fsz, fp) ) {
        free(*buf);
        return -1L;
    }

    /* Close the file */
    if( EOF == fclose(fp) ) {
        free(*buf);
        return -1L;
    }

    if( add_nul ) {
        /* Make sure the buffer is NUL-terminated, just in case */
        buf[fsz] = '\0';
    }

    /* Return the file size */
    return (long)fsz;
}


/*
 * Usage message for demo (in main(), below)
 */
void usage(void) {
    fputs("USAGE: ./slurp <filename>\n", stderr);
    exit(1);
}


/*
 * Demonstrates a call to 'slurp'.
 */
int main(int argc, char *argv[]) {
    long  file_size;
    char *buf;

    /* Make sure there is at least one command-line argument */
    if( argc < 2 ) {
        usage();
    }

    /* Try the first command-line argument as a file name */
    file_size = slurp(argv[1], &buf, false);

    /* Bail if we get a negative file size back from slurp() */
    if( file_size < 0L ) {
        perror("File read failed");
        usage();
    }

    /* Write to stdout whatever slurp() read in */
    (void)fwrite(buf, 1, file_size, stdout);

    /* Remember to free() memory allocated by slurp() */
    free( buf );
    return 0;
}

  • Zumindest unter Windows müssen Sie die Datei im “rb”-Modus öffnen, sonst gibt fread die falsche Nummer zurück. Und ich habe eine AccessViolation erhalten, wenn add_nul wahr war. Ich glaube, ich habe es behoben, indem ich Folgendes verwendet habe: (*buf)[fsz] = '\0';

    – Ray Hulha

    11. September 2015 um 13:38 Uhr

  • @RayHulha: fairer Punkt. Ich habe Windows seit Jahren nicht mehr verwendet und neige dazu, die Unterscheidung zwischen Binär- und Textmodus zu vergessen. Auch beim 2. Punkt hast du recht, da war im Original eine sachfremde Dereferenzierung (überzähliges „*“).

    – Emmett

    13. April 2016 um 5:33 Uhr

  • @Shark: Ja, es funktioniert. Ich kann nicht behaupten, dass es ausgiebig getestet wurde, aber es kompiliert ohne Warnungen unter gcc -std=c99 -pedantic -Wall -Wextra. Ich habe gerade zwei Beobachtungen von @RayHulha aufgenommen, aber ein direktes Kopieren und Einfügen und Kompilieren hat zuvor funktioniert. Es war nie wirklich als Bibliotheksfunktion gedacht, sondern nur als Demonstration. Ich habe es so geändert, dass es einen Dateinamen in der Befehlszeile akzeptiert, anstatt immer aus einer aufgerufenen Datei zu lesen foo.txtwas eher dem entspricht, was die Leute von einem vollständigen Programm erwarten.

    – Emmett

    13. April 2016 um 5:38 Uhr

  • Ich meine nichts Beleidigendes, aber das tut es eigentlich nicht. Es manchmal ruft undefiniertes Verhalten auf und leckt stark. Ich habe damit mehr als 3,5 GB Speicher verloren … Ich habe meine Problemumgehung eingefügt. Es wirklich tat funktioniert für die ersten paar Versuche gut, aber wie Sie sagten, ist es bei weitem nicht produktionsreif. Aber hey, es ist schön und hat seinen Trick für das Prototyping getan. Sollte auch für Hausaufgaben funktionieren 🙂

    – Hai

    13. April 2016 um 10:00 Uhr

  • Wo ist der Speicherverlust?

    – Ray Hulha

    13. April 2016 um 13:20 Uhr

Shamim Hafiz – Benutzeravatar von MSFT
Shamim Hafiz – MSFT

fgets() ist eine C-Funktion, die dazu verwendet werden kann.

Bearbeiten: Sie können auch die Verwendung von fread() in Betracht ziehen.

  • Unter Windows möchten Sie möglicherweise im Binärmodus öffnen, damit cr nicht übersetzt wird

    – Martin Beckett

    19. September 2010 um 19:16 Uhr

  • Nein tut es nicht. Es liest bis zum Zeilenumbruch oder Dateiende. Der gelesene Zeilenumbruch bleibt jedoch erhalten. Daher können Sie die gelesenen Zeichen direkt an das char-Array anhängen, und Zeilenumbrüche werden auf die gleiche Weise wie die Datei angezeigt.

    – Shamim Hafiz – MSFT

    19. September 2010 um 19:23 Uhr

  • Verwenden fgets für diesen Zweck macht keinen Sinn. Es wird viel komplizierter sein als eine Single fread und fehleranfälliger. Berücksichtigen Sie beispielsweise die zusätzliche Arbeit, die Sie leisten müssten, um eingebettete NUL-Bytes zu verarbeiten.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    19. September 2010 um 19:39 Uhr

  • @MartinBeckett OMFSM danke! Zufällige Zeichen am Ende meiner Zeichenfolge, 2 Stunden, in denen ich meinen Kopf gegen eine Wand geschmettert habe. Musste auch Inhalt hinzufügen[size] = ‘\0’; Am Ende bin ich mir nicht sicher, ob das Windows-spezifisch ist oder ob ich etwas anderes falsch mache.

    Benutzer170934

    17. Januar 2014 um 19:58 Uhr

Benutzeravatar von Shark
Hai

Da ich verwendet habe slurp() Ich hatte erwartet, dass es funktioniert, aber ein paar Tage später fand ich heraus, dass es nicht funktioniert.

Also für Leute, die gerne eine Lösung kopieren/einfügen möchten, um “den Inhalt einer Datei in ein Zeichen* zu bekommen”, ist hier etwas, das Sie verwenden können.

char* load_file(char const* path)
{
    char* buffer = 0;
    long length;
    FILE * f = fopen (path, "rb"); //was "rb"

    if (f)
    {
      fseek (f, 0, SEEK_END);
      length = ftell (f);
      fseek (f, 0, SEEK_SET);
      buffer = (char*)malloc ((length+1)*sizeof(char));
      if (buffer)
      {
        fread (buffer, sizeof(char), length, f);
      }
      fclose (f);
    }
    buffer[length] = '\0';
    // for (int i = 0; i < length; i++) {
    //     printf("buffer[%d] == %c\n", i, buffer[i]);
    // }
    //printf("buffer = %s\n", buffer);

    return buffer;
}

Benutzeravatar von sreaga
sreaga

Ich habe den folgenden Code verwendet, um die XML-Datei in einen Zeichenpuffer einzulesen, und ich musste \0 am Ende der Datei hinzufügen

FILE *fptr;
char *msg;
long length;
size_t read_s = 0;  
fptr = fopen("example_test.xml", "rb");
fseek(fptr, 0L, SEEK_END);
length = ftell(fptr);
rewind(fptr);
msg = (char*)malloc((length+1));
read_s = fread(msg, 1, length, fptr);
*(mip_msg+ read_s) = 0;
if (fptr) fclose(fptr);

1395590cookie-checkLesen der gesamten Textdatei in ein Char-Array in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy