it-swarm.com.de

C liest die Datei Zeile für Zeile

Ich habe diese Funktion geschrieben, um eine Zeile aus einer Datei zu lesen:

const char *readLine(FILE *file) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    const char *constLine = line;
    return constLine;
}

Die Funktion liest die Datei korrekt, und mit printf sehe ich, dass die constLine-Zeichenfolge auch richtig gelesen wurde.

Wenn ich jedoch die Funktion z. so was:

while (!feof(myFile)) {
    const char *line = readLine(myFile);
    printf("%s\n", line);
}

printf gibt Kauderwelsch aus. Warum?

142
lron

Wenn Ihre Aufgabe nicht darin besteht, die zeilenweise Lesefunktion zu erfinden, sondern nur, um die Datei zeilenweise zu lesen, können Sie ein typisches Code-Snippet verwenden, das die Funktion getline() enthält (siehe Handbuchseite hier ). :

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

int main(void)
{
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("/etc/motd", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        printf("Retrieved line of length %zu:\n", read);
        printf("%s", line);
    }

    fclose(fp);
    if (line)
        free(line);
    exit(EXIT_SUCCESS);
}
246
mbaitoff

In Ihrer readLine-Funktion geben Sie einen Zeiger auf das line-Array zurück (genau genommen einen Zeiger auf das erste Zeichen, aber der Unterschied ist hier nicht relevant). Da es sich um eine automatische Variable handelt (d. H. "Auf dem Stapel"), wird der Speicher zurückgefordert, wenn die Funktion zurückkehrt. Sie sehen Kauderwelsch, weil printf eigene Sachen auf den Stapel gelegt hat.

Sie müssen einen dynamisch zugewiesenen Puffer von der Funktion zurückgeben. Sie haben bereits eine, es ist lineBuffer; Sie müssen es lediglich auf die gewünschte Länge kürzen.

    lineBuffer[count] = '\0';
    realloc(lineBuffer, count + 1);
    return lineBuffer;
}

F&UUML;GTEhinzu (Antwort auf Folgefrage im Kommentar): readLine gibt einen Zeiger auf die Zeichen zurück, aus denen die Zeile besteht. Dieser Zeiger ist das, was Sie benötigen, um mit dem Inhalt der Zeile zu arbeiten. Es ist auch das, was Sie an free übergeben müssen, wenn Sie den Speicher dieser Zeichen nicht mehr benötigen. So können Sie die readLine-Funktion verwenden:

char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
   You can't use the value of `line` again (though you can assign a new value
   to the `line` variable if you want). */
19
Gilles
FILE* fp;
char buffer[255];

fp = fopen("file.txt", "r");

while(fgets(buffer, 255, (FILE*) fp)) {
    printf("%s\n", buffer);
}

fclose(fp);
16
Rob
//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");

//check if file exists
if (fh == NULL){
    printf("file does not exists %s", filename);
    return 0;
}


//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL)  {
    printf(line);
}
free(line);    // dont forget to free heap memory
14
RevoLab

readLine() gibt einen Zeiger auf die lokale Variable zurück, was zu undefiniertem Verhalten führt.

Um sich fortzubewegen, können Sie:

  1. Erstellen Sie eine Variable in der Aufruferfunktion und übergeben Sie ihre Adresse an readLine().
  2. Speicherplatz für line mithilfe von malloc() zuweisen - in diesem Fall ist line dauerhaft
  3. Verwenden Sie globale Variablen, obwohl dies im Allgemeinen eine schlechte Praxis ist
8
qrdl

Verwenden Sie fgets() , um eine Zeile aus einem Dateihandle zu lesen.

5
Raku Escape

Einige Dinge stimmen mit dem Beispiel nicht überein:

  • sie haben vergessen,\n zu Ihren printfs hinzuzufügen. Auch Fehlermeldungen sollten an stderr gehen, d. H. fprintf(stderr, ....
  • (keine große Sache, aber) Ziehen Sie die Verwendung von fgetc() anstelle von getc() in Betracht. getc() ist ein Makro, fgetc() ist eine richtige Funktion
  • getc() gibt eine int zurück, daher sollte ch als int deklariert werden. Dies ist wichtig, da der Vergleich mit EOF korrekt ausgeführt wird. Einige 8-Bit-Zeichensätze verwenden 0xFF als gültiges Zeichen (ISO-LATIN-1 wäre ein Beispiel) und EOF, die -1 ist, wird 0xFF sein, wenn sie einer char zugewiesen wird.
  • An der Leitung besteht ein möglicher Pufferüberlauf

    lineBuffer[count] = '\0';
    

    Wenn die Zeile genau 128 Zeichen lang ist, ist count an dem Punkt, der ausgeführt wird, 128 Zeichen.

  • Wie bereits erwähnt, ist line ein lokal deklariertes Array. Sie können keinen Zeiger darauf zurückgeben.

  • strncpy(count + 1) kopiert höchstens count + 1-Zeichen, wird jedoch beendet, wenn '\0' angezeigt wird. Da Sie lineBuffer[count] auf '\0' setzen, wissen Sie, dass count + 1 nie erreicht wird. Wenn dies jedoch der Fall ist, wird '\0' nicht mit einem Abschluss versehen. Sie müssen es also tun. Sie sehen oft etwas wie das Folgende:

    char buffer [BUFFER_SIZE];
    strncpy(buffer, sourceString, BUFFER_SIZE - 1);
    buffer[BUFFER_SIZE - 1] = '\0';
    
  • wenn Sie malloc() eine Zeile zurückgeben (anstelle Ihres lokalen char-Arrays), sollte Ihr Rückgabetyp char* sein - löschen Sie die const.

4
JeremyP
void readLine(FILE* file, char* line, int limit)
{
    int i;
    int read;

    read = fread(line, sizeof(char), limit, file);
    line[read] = '\0';

    for(i = 0; i <= read;i++)
    {
        if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
        {
            line[i] = '\0';
            break;
        }
    }

    if(i != read)
    {
        fseek(file, i - read + 1, SEEK_CUR);
    }
}

was ist mit diesem?

2
Taner Mansur

Hier sind meine Stunden ... Lesen der ganzen Datei Zeile für Zeile.

char * readline(FILE *fp, char *buffer)
{
    int ch;
    int i = 0;
    size_t buff_len = 0;

    buffer = malloc(buff_len + 1);
    if (!buffer) return NULL;  // Out of memory

    while ((ch = fgetc(fp)) != '\n' && ch != EOF)
    {
        buff_len++;
        void *tmp = realloc(buffer, buff_len + 1);
        if (tmp == NULL)
        {
            free(buffer);
            return NULL; // Out of memory
        }
        buffer = tmp;

        buffer[i] = (char) ch;
        i++;
    }
    buffer[i] = '\0';

    // Detect end
    if (ch == EOF && (i == 0 || ferror(fp)))
    {
        free(buffer);
        return NULL;
    }
    return buffer;
}

void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
    puts(s);
    free(s);
    printf("\n");
}
}

int main()
{
    char *fileName = "input-1.txt";
    FILE* file = fopen(fileName, "r");
    lineByline(file);
    return 0;
}
2
Sam
const char *readLine(FILE *file, char* line) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    return line;

}


char linebuffer[256];
while (!feof(myFile)) {
    const char *line = readLine(myFile, linebuffer);
    printf("%s\n", line);
}

beachten Sie, dass die 'line'-Variable in der aufrufenden Funktion deklariert und dann übergeben wird, damit Ihre readLine-Funktion den vordefinierten Puffer füllt und ihn nur zurückgibt. Auf diese Weise funktionieren die meisten C-Bibliotheken.

Es gibt andere Möglichkeiten, die mir bekannt sind: 

  • definieren von char line[] als statisch (static char line[MAX_LINE_LENGTH]-> es wird den Wert behalten, nachdem die Funktion zurückgegeben wurde). -> bad, Die Funktion ist nicht wiedereintrittsfähig, und es kann eine Race-Bedingung auftreten. -> Wenn Sie zweimal von zwei Threads aufrufen, überschreibt es die Ergebnisse
  • malloc()ing der char-Zeile [] und es in aufrufenden Funktionen freigeben -> zu viele teure mallocs, und die Übertragung der Verantwortung für die Freigabe des Puffers an eine andere Funktion (die eleganteste Lösung ist der Aufruf von malloc) und free für alle Puffer in derselben Funktion)

Übrigens, das "explizite" Casting von char* nach const char* ist redundant.

btw2, es ist nicht notwendig, den lineBuffer malloc() zu benennen, definieren Sie ihn einfach char lineBuffer[128], so dass Sie ihn nicht freigeben müssen

btw3 verwendet keine Stack-Arrays mit dynamischer Größe (definiert das Array als char arrayName[some_nonconstant_variable]). Wenn Sie nicht genau wissen, was Sie tun, funktioniert es nur in C99.

1
nothrow

Sie sollten die ANSI-Funktionen zum Lesen einer Zeile verwenden, z. fgets Nach dem Aufruf benötigen Sie free () im Aufrufkontext, zB:

...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...

const char *readLine(FILE *file)
{
  char *lineBuffer=calloc(1,1), line[128];

  if ( !file || !lineBuffer )
  {
    fprintf(stderr,"an ErrorNo 1: ...");
    exit(1);
  }

  for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
  {
    if( strchr(line,'\n') ) *strchr(line,'\n')=0;
    lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
    if( !lineBuffer )
    {
      fprintf(stderr,"an ErrorNo 2: ...");
      exit(2);
    }
  }
  return lineBuffer;
}
1
user411313

Methode zum Lesen und Abrufen von Inhalten aus einer Datei implementieren (input1.txt)

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

void testGetFile() {
    // open file
    FILE *fp = fopen("input1.txt", "r");
    size_t len = 255;
    // need malloc memory for line, if not, segmentation fault error will occurred.
    char *line = malloc(sizeof(char) * len);
    // check if file exist (and you can open it) or not
    if (fp == NULL) {
        printf("can open file input1.txt!");
        return;
    }
    while(fgets(line, len, fp) != NULL) {
        printf("%s\n", line);
    }
    free(line);
}

Ich hoffe das hilft. Viel Spaß beim Codieren!

1
Nhat Dinh

Stellen Sie eine portable und generische read_line -Funktion bereit, und Sie können den Inhalt der Zeile zeilenweise verarbeiten.

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

void
read_line(const char *filename,
          size_t linecap,
          int delimiter,
          void (*process_line)(const char *line, ssize_t linelen)) {
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror(filename);
        return;
    }
    int c;
    char *line = malloc(linecap);
    if (0 == line) {
        perror("linecap");
        goto close_exit;
    }
    char *p = line;
    ssize_t linelen;
    while (EOF != (c = fgetc(file))) {
        if (delimiter == c) {
            *p = delimiter, *++p = 0;
            process_line(line, linelen+1);
            p = line;
            linelen = 0;
        } else {
            *p++ = c;
            linelen++;
        }
    }
    free(line);
    if (ferror(file)) {
        perror(filename);
        goto close_exit;
    }
 close_exit:
    fclose(file);
}

void
print_line(const char *line, ssize_t linelen) {
    fwrite(line, 1, linelen, stdout);
    fflush(stdout);
}

int
main(int argc, char **argv) {
  read_line("/a/b/c/some.txt", 16, '\n', print_line);
  return 0;
}
0
南山竹

Mein Gerät von Grund auf neu:

FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);

size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
    bytes_read = strlen(buf);
    // if line length larger than size of line buffer
    if (linesize + bytes_read > nbytes) {
        char *tmp = line;
        nbytes += nbytes / 2;
        line = (char *) malloc(nbytes);
        memcpy(line, tmp, linesize);
        free(tmp);
    }
    memcpy(line + linesize, buf, bytes_read);
    linesize += bytes_read;

    if (feof(pFile) || buf[bytes_read-1] == '\n') {
        handle_line(line);
        linesize = 0;
        memset(line, '\0', nbytes);
    }
}

free(buf);
free(line);
0
tjeubaoit

Sie machen den Fehler, einen Zeiger auf eine automatische Variable zurückzugeben. Die Variablenzeile wird im Stack zugewiesen und bleibt nur so lange gültig, wie die Funktion läuft. Sie dürfen keinen Zeiger darauf zurückgeben, weil Sobald es zurückkehrt, wird der Speicher an anderer Stelle weitergegeben.

const char* func x(){
    char line[100];
    return (const char*) line; //illegal
}

Um dies zu vermeiden, geben Sie entweder einen Zeiger auf den Speicher zurück, der sich auf dem Heap befindet, z. lineBuffer und es sollte in der Verantwortung des Benutzers liegen, free () aufzurufen, wenn er damit fertig ist . Alternativ können Sie den Benutzer bitten, Ihnen eine Speicheradresse als Argument zu übergeben, auf die der Zeileninhalt geschrieben werden soll.

0
Lefteris E

Ich möchte einen Code von Boden 0, also habe ich dies getan, um den Inhalt des Wörterbuchs Zeile für Zeile zu lesen.

char temp_str [20]; // Sie können die Puffergröße entsprechend Ihren Anforderungen ändern. Die Länge einer einzelnen Zeile in einer Datei.

Hinweis Ich habe den Puffer jedes Mal mit Nullzeichen initialisiert, wenn ich zeile lese. Diese Funktion kann automatisiert werden, aber da brauche ich einen Proof of Concept und möchte ein Programm Byte für Byte entwerfen 

#include<stdio.h>

int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
 i=0;
  char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
  temp_ch=fgetc(fp);
  temp_str[i]=temp_ch;
  i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}
0
Mohit Dabas