C Beliebig lange *.txt-Datei einlesen

D4L4!L4M4

Captain
Registriert
Jan. 2006
Beiträge
3.615
Guten Morgen ;)

da ich auch nach langer Internet-Recherche nichts gefunden habe frage ich mal hier und hoffe ihr könnt mir helfen.

Sprache ist C (nicht C++!). Und zwar möchte ich eine beliebig lange Textdatei einlesen können, sprich die Länge der Datei kann variieren.

Es handelt sich um eine Datei in der ein String mit beliebiger Länge stehen kann, ohne Zeilenumbrüche ("\n"). Der gesamte String steht also in einer Zeile.

Im Moment läuft das in meinem Programm noch so ab:
Code:
        char text [[B]200[/B]];
        FILE *datei;
	datei = fopen ("text.txt", "r");
	if (datei != NULL)
	{
		fgets(text, [B]200[/B], datei);
		/* String muss mit Nullbyte abgeschlossen sein */
		n1[strlen(text)] = '\0';
		fclose (Datei);
	}

Nun besteht hier natürlich dass Problem dass ich die Länge des Strings auf 200 Zeichen begrenzt hab. Das char-Array hat nur 200 Felder und von der Datei werden auch nur 200 Zeichen eingelesen.

Ich würde es jetzt gerne mit dynamischer Speicherverwaltung (malloc, realloc) so handhaben, dass das Programm selbst herausfindet wie lang der String in der Datei ist und dementsprechend genügend Speicher für das char-Array bereitstellt.

Leider finde ich im Internet (z.b. Open Galileo Books - C von A bis Z) nur Anleitungen dafür wie man das handhabt wenn die Zeichen von Hand über die Konsole eingegeben werden. In meinem Fall habe ich ja aber immer eine *.txt-Datei aus der gelesen werden soll.

Ich bin dankbar für jedwede Hilfe :)

Schönen Sonntag wünsch ich allerseits,

MfG Tim
 
Code:
        int len = 200;
        char *text = malloc(200*sizeof(char));

        FILE *datei;
	datei = fopen ("text.txt", "r");

	while(datei != EOF)
	{
		fgets(text, len, Datei);
                len+=len;
                text = realloc(text, len*sizeof(char));		

		fclose (Datei);
	}

Meinst du so? Tut mir leid, aber ich bin noch dabei mich in C einzuarbeiten, deswegen bin ich mir an manchen Stellen noch unsicher.
"Weiß" denn die Schleife dass "fgets" noch nicht am Ende der Datei angelangt ist?

Auf jeden Fall schon mal vielen Dank für deine Antwort, "EOF" ist auf jeden Fall ein Begriff den ich mir jetzt mal näher angucke ;)

MfG Tim

edit:
Oder geht das vielleicht so. Erscheint mir sinnvoller, werde ich mal im Programm testen:

Code:
        char text [200];
        FILE *datei;
	datei = fopen ("text.txt", "r");
	while (frets(text, 200, datei) != EOF)
	{
		len+=len;
	}
 
Zuletzt bearbeitet:
hab da mal aus einem meiner alten programme einen abschnitt rauskopiert..
ob es besser oder schlechter performt als mit der schleifenvariante vonDigital_D99 kann ich aber nicht sagen :)


Code:
// ANFANG - Dateigrösse bestimme

    if (fseek( datei_in, 0L, SEEK_END ) != 0) // ans Ende springen
    {
        printf("\nERROR in SEEK_END");
        fclose(datei_in);
        return 3;
    }
    if ((len=ftell( datei_in ))  < 0L)
    {
        printf("\nERROR in ftell ");
        fclose(datei_in);
        return 3;
    }
    if (fseek( datei_in, 0L, SEEK_SET ) != 0) // an den Anfang zurück
    {
        printf("\nERROR in SEEK_SET");
        fclose(datei_in);
        return 3;
    }

    // ENDE - Dateigrösse bestimme





    // Speicher für Puffer anfordern
    if((puffer_ein=(char*)malloc(sizeof(char)*len+8)) == NULL)   // Reserivert zusetzlich 8 zeichen als reserve
    {
        printf("\nERROR: Cant't allocate memory");
        fclose(datei_in);
        return 4;
    }
    // ENDE Speicher für Puffer anfordern
 
Code:
#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    unsigned int len_max = 128;
    unsigned int current_size = 0;
    char *pStr = malloc(len_max);
    current_size = len_max;
    ptr = fopen("/etc/hosts","r");

    if(pStr != NULL)
    {
	int c = EOF;
	unsigned int i =0;
	while (( c = fgetc(ptr) ) != '\n' && c != EOF)
	{
		pStr[i++]=(char)c; 
		//if i reached maximize size then realloc size
		if(i == current_size)
		{
                        current_size = i+len_max;
			pStr = realloc(pStr, current_size);
		}
	}
 
	pStr[i] = '\0';
        //free it 
	free(pStr);
	pStr = NULL; 
    }
    return 0;
}

So könnte es aussehen, allerdings ungetestet.
 
@c0mp4ct
Das sieht gut aus, vielen Dank, ich werde es mal testen und berichten ;).

@Digital_D99
Danke sehr, ich hoffe ich krieg es mit der kombinierten Lösung von dir und c0mp4ct hin ;)

@Salvation
Auch dir vielen Dank, ggf. komm darauf zurück, aber ich hoffe du verzeihst mir wenn ich erst mal die anderen Vorschläge teste, die sehen (für mich) einfacher aus.


Ich werd mich noch mal melden obs funktioniert oder nicht, aber auf jeden Fall immer wieder schön wie schnell einem hier geholfen wird.

MfG Tim
 
@
brauchbar wenn die anderen die Hausaufgabe machen, gel
 
die schleife von dir sollte eher so ausschauen.. bin aber auch kein c-profi

Code:
int len = 0;
char *text = NULL;
FILE *datei=NULL;
int c=0;

datei = fopen ("text.txt", "rb");  // ich würde binär auslesen wegen zeilenumbruch

	while(c != EOF)
	{
		c=getc(datei); //getc ist viel schneller als fgetc bei einzelnen zeichen
                len++;
	}

text = malloc(len*sizeof(char));		

fclose (Datei);


PS: ok sind nur ein paar tips zum probieren :)
EDIT: sorry ein kleiner fehler war drinn.. und ist korrigiert
 
Zuletzt bearbeitet:
Was möchtest du da kombinieren? Der von mir gepostete Code enthält doch schon die Schleife von Digital_D99.

@Salvation

but when you are reading from a stream that is not interactively produced by a human, fgetc is probably better.
Quelle: Link, ganz unten, also bitte vorsicht mit solchen Aussagen.
 
Zuletzt bearbeitet:
DerKleine49 schrieb:
@
brauchbar wenn die anderen die Hausaufgabe machen, gel

Es ist nur ein sehr kleiner Teil einer wesentlich umfangreicheren Aufgabe, bei dem ich seit Tagen auf keinen grünen Zweig komme, deswegen hab ich mal hier gefragt ;)

@c0mp4ct
Ich hatte das von Digital_D99 schon bei mir eingebaut, deswegen kombinieren ;)

@Salvation
Ja, ich glaub darauf läuft es ungefähr hinaus, bin aber noch am testen.

MfG Tim

edit:

Also noch mal vielen Dank, es funktioniert, ich habe es jetzt so gelöst:

Code:
while(fgetc(datei)!=EOF)
{
       len++;
}

Mit der Schleife kann ich jetzt einfach die Länge des Strings in der Datei bestimmen und fordere dann dementsprechend im weiteren Programmverlauf Speicher an.

Und ich sags noch mal, schön dass einem hier so schnell geholfen wird :)

Schönen Sonntag noch wünsche ich allerseits!
 
Zuletzt bearbeitet:
@c0mp4ct

hmm.. ich verwende trotzdem getc da ich mit tests rausgefunden habe dass getc beim mir um faktor 12! schneller war als fgetc was irgenwie damit zu tun hat dass getc ein macro ist und fgetc eine funktion...

was ist denn da genau das problem wenn man nur dateien einliest?
 
Zuletzt bearbeitet:
Bloß kein getc oder fgetc verwenden! Das ist beides die langsamst mögliche Lösung!
Man verwendet hierfür fread!

Ebenfalls sollte realloc auf jeden Fall vermieden werden. Erst die Dateigröße auslesen und danach gleich einen Puffer der richtigen Größe anfordern! realloc kann zu unnötigen Kopiervorgängen führen, die das Prorgamm einfach nur unnötig langsam machen!
 
@IceMatrix
realloc habe ich ja jetzt vermieden indem ich wie oben im Quelltest-Ausschnitt erst die benötigte Länge bestimme und dann entsprechend Speicherplatz anfordere.

Über fread werde ich mich mal informieren und dann ggf. so implementieren, danke!

MfG Tim
 
Oder du machst einfach:
Code:
fseek(file, 0, SEEK_END); // seek to end of file
size = ftell(file); // get current file pointer
fseek(file, 0, SEEK_SET); //back to the beginning of the file

// allocate memory and start reading the file
in dem Fall hat size, ein integer die datei groesse und du kannst ganz normal die datei einlesen
Ausserdem moechtest du fread zum einlesen von block data benutzen und fwrite zum schreiben von block data benutzen
fscan und fprintf sind zum lesen/schreiben von streams anstatt von block data zu benutzen
 
Zuletzt bearbeitet:
Zurück
Oben