Datei Zeilenweise einlesen



  • Hallo zusammen,

    mein Ziel ist es eine Datei zeilenweise auszulesen. Dabei sollen aber folgende Kriterien erfüllt sein:
    - <newline> entfernen
    - leere Zeilen "überlesen" also direkt mit der nächsten Zeile weitermachen
    - die Funktion soll folgendermaßen anzuwenden sein:

    /* gibt es eine nächste Zeile? -> einlesen */
    while (reads(str, 1024, stream)) {
    	printf("%s\n", str);
    }
    

    Hier die Funktion:

    #include <stdio.h>
    #include <string.h>
    
    int reads(char *str, int num, FILE *stream) {
    	int len;
    	while(fgets(str, num, stream) != NULL) {
    		len = strlen(str) - 1;
    		if (str[len] == '\n') {
    			str[len] = '\0';
    			if (len == 0) {
    				continue;
    			}
    		}
    		return -1;
    	}
    	return 0;
    }
    

    Meine Fragen sind nun:
    - zurzeit ist ein festes Limit mit "num" gegeben wann eine Zeile aufgesplittet wird. Es soll aber eigentlich die komplette Zeile ohne Unterteilung in den String kopiert werden. Hat jemand Tipps wie das performant zu realisieren ist?
    - kann das zeilenweise einlesen noch weiter vereinfacht werden?

    Danke schonmal für die Antworten!



  • enox schrieb:

    - leere Zeilen "überlesen" also direkt mit der nächsten Zeile weitermachen

    Sind damit auch Zeilen gemeint, die nur aus Whitespace besthehen?

    enox schrieb:

    - zurzeit ist ein festes Limit mit "num" gegeben wann eine Zeile aufgesplittet wird. Es soll aber eigentlich die komplette Zeile ohne Unterteilung in den String kopiert werden. Hat jemand Tipps wie das performant zu realisieren ist?

    Dann musst du mit malloc/realloc arbeiten.
    Das ist nicht perfomant und deinen Aufruf musst du auch umgestalten, da du ja den neuen SpeicherPlatz zurückgeben musst.
    Du darfst dann auch nicht das free vergessen.
    Da du das '\n' entfernst, kannst du in der rufenden Funktion auch nicht mehr erkennen, ob die Zeile komplett eingelesen wurde (oder du gibst einen anderen Wert zurück z.B. 2)

    enox schrieb:

    - kann das zeilenweise einlesen noch weiter vereinfacht werden?

    Du möchtest es doch so kompliziert haben.

    Was soll denn mit den Zeilen gemacht werden?
    Nur das printf aus deinem Beispiel sicher nicht.



  • DirkB schrieb:

    Sind damit auch Zeilen gemeint, die nur aus Whitespace besthehen?

    Danke für den Tipp, hab ich gar nicht drauf geachtet. Hab die Funktion aktualisiert:

    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    
    int reads(char *str, int num, FILE *stream) {
    	int len;
    	while(fgets(str, num, stream) != NULL) {
    		len = strlen(str) - 1;
    
    		/* delete right whitespaces */
    		while (len >= 0 && isspace(str[len])) {
    			len--;
    		}
    
    		/* if empty string */
    		if (len < 0) {
    			continue;
    		} else {
    			str[len + 1] = '\0';
    		}
    
    		return 1; /* line read successfully */
    	}
    	return 0; /* no next line */
    }
    

    DirkB schrieb:

    Dann musst du mit malloc/realloc arbeiten.
    Das ist nicht perfomant und deinen Aufruf musst du auch umgestalten, da du ja den neuen SpeicherPlatz zurückgeben musst.
    Du darfst dann auch nicht das free vergessen.
    Da du das '\n' entfernst, kannst du in der rufenden Funktion auch nicht mehr erkennen, ob die Zeile komplett eingelesen wurde (oder du gibst einen anderen Wert zurück z.B. 2)

    Hab mich grad dran gesetzt, sollte mit der Funktions-Signatur aber funktionieren.



  • DirkB schrieb:

    Dann musst du mit malloc/realloc arbeiten.

    enox schrieb:

    Hab mich grad dran gesetzt, sollte mit der Funktions-Signatur aber funktionieren.

    Glaub ich nicht. Ich denke, dann brauchst Du

    int reads(char **str, int num, FILE *stream)
    


  • Hab jetzt auch gemerkt, dass es mit der Signatur "etwas schwierig" werden könnte.

    Bin gerade dabei die Funktion ummzuscheiben, so dass ein char buffer pointer übergeben wird:

    typedef struct char_buffer {
        char *data;
        int size;
        int err; /* no error -> 0 */
    } char_buffer;
    
    int reads(char_buffer *buf, FILE *stream);
    

    So kann die Funktion wie gewohnt verwendet werden und die Überprüfung auf Fehler wird auch erleichtert.

    char_buffer *buf = create_buffer();
    
    while(reads(buf, pfile)) {
        /* ... */
    }
    
    if (buf->err) {
        /* ... */
    }
    
    dispose_buffer(buf);
    

    Bin grade noch bei der Implementierung, werde die Ergebnisse noch posten.
    Was haltet ihr von der Design-Entscheidung? Was spricht dagegen?


Log in to reply