Wie soll ich in C eine Textdatei lesen und alle Zeichenfolgen drucken?

Lesezeit: 7 Minuten

Richardaums Benutzeravatar
richardaum

Ich habe eine Textdatei mit dem Namen test.txt

Ich möchte ein C-Programm schreiben, das diese Datei lesen und den Inhalt auf der Konsole ausgeben kann (vorausgesetzt, die Datei enthält nur ASCII-Text).

Ich weiß nicht, wie ich die Größe meiner String-Variablen erhalte. So was:

char str[999];
FILE * file;
file = fopen( "test.txt" , "r");
if (file) {
    while (fscanf(file, "%s", str)!=EOF)
        printf("%s",str);
    fclose(file);
}

Die Größe 999 funktioniert nicht, weil die von zurückgegebene Zeichenfolge fscanf kann größer sein. Wie kann ich das lösen?

Am einfachsten ist es, ein Zeichen zu lesen und direkt nach dem Lesen zu drucken:

int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
    while ((c = getc(file)) != EOF)
        putchar(c);
    fclose(file);
}

c ist int oben, da EOF ist eine negative Zahl und eine Ebene char vielleicht unsigned.

Wenn Sie die Datei in Blöcken lesen möchten, aber ohne dynamische Speicherzuweisung, können Sie Folgendes tun:

#define CHUNK 1024 /* read 1024 bytes at a time */
char buf[CHUNK];
FILE *file;
size_t nread;

file = fopen("test.txt", "r");
if (file) {
    while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
        fwrite(buf, 1, nread, stdout);
    if (ferror(file)) {
        /* deal with error */
    }
    fclose(file);
}

Die zweite Methode oben ist im Wesentlichen, wie Sie eine Datei mit einem dynamisch zugewiesenen Array lesen:

char *buf = malloc(chunk);

if (buf == NULL) {
    /* deal with malloc() failure */
}

/* otherwise do this.  Note 'chunk' instead of 'sizeof buf' */
while ((nread = fread(buf, 1, chunk, file)) > 0) {
    /* as above */
}

Ihre Methode der fscanf() mit %s da das Format Informationen über Leerzeichen in der Datei verliert, kopiert es nicht genau eine Datei in stdout.

  • Es ist möglich, Daten aus einer Datei zu lesen, ohne diese Datei in c/c++ zu öffnen??

    – Sagar Patel

    27. Oktober 2015 um 11:13 Uhr


  • Was ist, wenn die Textdatei durch Kommas getrennte Ganzzahlwerte enthält? Als was wäre der Code, können Sie Ihre Antwort auch damit bearbeiten.

    – Mohsin

    21. Oktober 2016 um 20:43 Uhr

  • Das obige funktioniert für jede Art von Textdatei. Wenn Sie die Zahlen aus einer CSV-Datei analysieren möchten, ist das ein anderes Problem.

    – Alok Singhal

    22. Oktober 2016 um 3:34 Uhr

  • @overexchange Die Frage spricht nicht über Zeilen – es geht darum, eine Datei zu lesen und ihren Inhalt zu kopieren stdout.

    – Alok Singhal

    3. Januar 2017 um 3:35 Uhr

  • @shjeff Eine Datei darf kein EOF-Zeichen enthalten. Beachten Sie, dass c ist int, und C wird das garantieren EOF ist keinem gültigen Zeichen gleich.

    – Alok Singhal

    22. November 2017 um 22:14 Uhr


Benutzeravatar von lfzawacki
lfzawacki

Hier gibt es viele gute Antworten zum Lesen in Blöcken. Ich zeige Ihnen nur einen kleinen Trick, der den gesamten Inhalt auf einmal in einen Puffer liest und ausgibt.

Ich sage nicht, dass es besser ist. Ist es nicht, und wie bei Ricardo kann es manchmal schlecht sein, aber ich finde es ist eine nette Lösung für die einfachen Fälle.

Ich habe es mit Kommentaren gesprenkelt, weil viel los ist.

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

char* ReadFile(char *filename)
{
   char *buffer = NULL;
   int string_size, read_size;
   FILE *handler = fopen(filename, "r");

   if (handler)
   {
       // Seek the last byte of the file
       fseek(handler, 0, SEEK_END);
       // Offset from the first to the last byte, or in other words, filesize
       string_size = ftell(handler);
       // go back to the start of the file
       rewind(handler);

       // Allocate a string that can hold it all
       buffer = (char*) malloc(sizeof(char) * (string_size + 1) );

       // Read it all in one operation
       read_size = fread(buffer, sizeof(char), string_size, handler);

       // fread doesn't set it so put a \0 in the last position
       // and buffer is now officially a string
       buffer[string_size] = '\0';

       if (string_size != read_size)
       {
           // Something went wrong, throw away the memory and set
           // the buffer to NULL
           free(buffer);
           buffer = NULL;
       }

       // Always remember to close the file.
       fclose(handler);
    }

    return buffer;
}

int main()
{
    char *string = ReadFile("yourfile.txt");
    if (string)
    {
        puts(string);
        free(string);
    }

    return 0;
}

Lassen Sie mich wissen, ob es nützlich ist oder Sie etwas daraus lernen könnten 🙂

  • Sollte es nicht lesen buffer[string_size] = '\0'; Anstatt von string_size+1? Afaik der eigentliche String geht aus 0 zu string_size-1 und die \0 Charakter muss also sein string_sizeRechts?

    – Emilia Bopp

    3. Juni 2014 um 9:54 Uhr

  • Verwenden ftell und fseek um die Größe einer Datei zu finden, ist unsicher: securecoding.cert.org/confluence/display/seccode/…

    – Joakim

    1. Juli 2014 um 9:05 Uhr


  • Eine Sache, die Sie unter Windows beachten sollten, string_size möglicherweise nicht gleich read_size wenn die Datei im Textmodus geöffnet wird. Ich zitiere aus diesem Link (bytes.com/topic/c/answers/479976-interesting-thing-about-fread) Under Windows, a text file has two characters for end-of-line (CR+LF -- "\r\n"), but the C library will strip the CR when reading a file open in text mode, so that the program will only see LF ('\n'). The stat() call is returning the "real" size if the file, while the returns from fread() have stripped the CR.

    – Ärger

    7. September 2015 um 0:45 Uhr

  • Dieser Code enthält ein Speicherleck, Sie schließen die Datei nie. Es fehlt ein fclose(handle)

    – Joakim

    10. April 2016 um 22:16 Uhr

  • Du könntest benutzen calloc(2) statt malloc(1) um zu überspringen, dass der Null-Terminator gesetzt werden muss.

    Benutzer376845

    7. Februar 2018 um 7:55 Uhr


Benutzeravatar von Sagar Shah
Sagar Schah

Geben Sie die Zeichen stattdessen einfach direkt auf der Konsole aus, da die Textdatei möglicherweise sehr groß ist und Sie möglicherweise viel Speicher benötigen.

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

int main() {

    FILE *f;
    char c;
    f=fopen("test.txt","rt");

    while((c=fgetc(f))!=EOF){
        printf("%c",c);
    }

    fclose(f);
    return 0;
}

Benutzeravatar von DVK
DVK

Verwenden Sie “read()” anstelle von fscanf:

ssize_t read(int fildes, void *buf, size_t nbyte);

BEZEICHNUNG

Die Funktion read() soll versuchen zu lesen nbyte Bytes aus der Datei, die dem offenen Dateideskriptor zugeordnet ist, fildesin den Puffer, auf den gezeigt wird buf.

Hier ist ein Beispiel:

http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html

Arbeitsteil aus diesem Beispiel:

f=open(argv[1],O_RDONLY);
while ((n=read(f,l,80)) > 0)
    write(1,l,n);

Ein alternativer Ansatz ist zu verwenden getc/putc 1 Zeichen auf einmal lesen/schreiben. Viel weniger effizient. Ein gutes Beispiel: http://www.eskimo.com/~scs/cclass/notes/sx13.html

Edus Benutzer-Avatar
Edu

Sie können verwenden fgets und begrenzen Sie die Größe des gelesenen Strings.

char *fgets(char *str, int num, FILE *stream);

Sie können die ändern while in deinem Code an:

while (fgets(str, 100, file)) /* printf("%s", str) */;

Benutzeravatar von RBerteig
RBerteig

Zwei Ansätze fallen mir spontan ein.

Erstens nicht verwenden scanf. Verwenden fgets() die einen Parameter akzeptiert, um die Puffergröße anzugeben, und die alle Zeilenumbruchzeichen intakt lässt. Eine einfache Schleife über die Datei, die den Pufferinhalt druckt, sollte die Datei natürlich intakt kopieren.

Zweitens verwenden fread() oder das gebräuchliche C-Idiom mit fgetc(). Diese würden die Datei in Blöcken fester Größe oder jeweils ein einzelnes Zeichen verarbeiten.

Wenn Sie die Datei über durch Leerzeichen getrennte Zeichenfolgen verarbeiten müssen, verwenden Sie eine von beiden fgets oder fread um die Datei zu lesen, und so etwas strtok um den Puffer bei Leerzeichen aufzuteilen. Vergessen Sie nicht, den Übergang von einem Puffer zum nächsten zu handhaben, da Ihre Zielzeichenfolgen wahrscheinlich die Puffergrenze überspannen.

Wenn eine externe Anforderung zur Verwendung besteht scanf Um den Lesevorgang durchzuführen, begrenzen Sie dann die Länge der möglicherweise gelesenen Zeichenfolge mit einem Genauigkeitsfeld im Formatbezeichner. In Ihrem Fall mit einem 999-Byte-Puffer, sagen Sie dann scanf("%998s", str); Dadurch werden höchstens 998 Zeichen in den Puffer geschrieben, sodass Platz für das Null-Terminator bleibt. Wenn einzelne Zeichenfolgen länger als Ihr Puffer zulässig sind, müssen Sie sie in zwei Teilen verarbeiten. Wenn nicht, haben Sie die Möglichkeit, den Benutzer höflich über einen Fehler zu informieren, ohne eine Pufferüberlauf-Sicherheitslücke zu erzeugen.

Unabhängig davon sollten Sie immer die Rückgabewerte validieren und darüber nachdenken, wie Sie mit fehlerhaften, böswilligen oder einfach falsch formatierten Eingaben umgehen.

Benutzeravatar von Marco Ciaramella
Marco Ciaramella

Ich benutze diese Version

char* read(const char* filename){
    FILE* f = fopen(filename, "rb");
    if (f == NULL){
        exit(1);
    }
    fseek(f, 0L, SEEK_END);
    long size = ftell(f)+1;
    fclose(f);
    f = fopen(filename, "r");
    void* content = memset(malloc(size), '\0', size);
    fread(content, 1, size-1, f);
    fclose(f);
    return (char*) content;
}

1422690cookie-checkWie soll ich in C eine Textdatei lesen und alle Zeichenfolgen drucken?

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

Privacy policy