Dateigröße auslesen und Inhalt ausgeben



  • mahlzeit!

    folgender code und dazugehörige frage:

    FILE *fpointer;
    fpointer = fopen("C:/.../Desktop/hallo.txt", "r");
    char string[80];
    for (int i = 0; i < 10; i++)
    {
          fscanf(fpointer, "%s", string);
          printf("%s \n", string);
    }
    fclose(fpointer);
    

    in der textdatei "hallo.txt" steht folgendes drin:

    Hallo Welt!
    Wie geht es dir?
    

    die aufgabe besteht darin, eine datei vom desktop zu öffnen und den inhalt zeilenweise auszugeben. man geht von 80 zeichen pro zeile aus.

    erste ideen:
    erst einmal die anzahl der zeichen oder anzahl der zeilen in der datei bestimmen.
    hätte ich die anzahl der zeichen z.b. mit fgetc(fpointer) oder anzahl der zeilen vor dem auslesen , könnte ich schon mal die for-schleife effizienter gestalten. diese läuft jetzt ja 10 mal. habe ich nur 5 zeilen text in meiner datei, sind 5 durchgänge verschenkt. so war mein gedanke zumindest.

    ich habe jetzt mit vielen funktionen herumgespielt. die anzahl an bytes in der datei beim auslesen habe ich irgendwie nicht hinbekommen. da hat er nur ganz konfuse zahlen als ergebnis gebracht.
    allerdings habe ich das auslesen zeilen mit:

    int cnt = 1;                     //1 wegen erster zeile 
    for (int i = 0; i < 10; i++)    
    {
        if(fgetc(fpointer) == EOF) cnt++;
    }
    printf("%d", cnt);
    

    hinbekommen. wenn auch nicht ganz korrekt (siehe unten --> problem mit der formatierung), da in der datei 2 zeilen sind und mein "cnt" 5 irgendwie anzeigt. vielleicht lieg ich auch völlig daneben. 😕

    man müsste ja theoretisch vor dem auslesen der datei, die größe bestimmen können um der for-schleife effiziente parameter zu geben. theoretisch! 😃
    geht ja aber scheinbar erst, wenn man diese ausliest mit z.b. einer for-schleife eben.
    ich hoffe ihr wisst was ich in etwa meine.

    mir kamen auch ideen dieses problem mit malloc() oder einer zweiten schleife zu händeln. aber eine extra schleife zum zählen der größe um mit dieser größe dann effizient den inhalt mittels zweiter schleife auszulesen is ja völliger nonsens.
    desweiteren funktionen w.z.b. fseek(), ftell(), st_size gelesen. aber das sagt mir gleich mal gar nix. bin dahingehend kein pro!
    vielleicht habt ihr einen guten gedanken.

    zweites problem, was auf dem ersten aufbaut:
    wenn ich die schleife jetzt 10 mal durchlaufen lasse und ich habe in meiner textdatei nur 2 zeilen (wie im bsp. oben), dann gibt er mir folgendes aus:

    Hallo
    Welt!
    Wie
    geht
    es
    dir?
    dir?
    dir?
    dir?
    dir?
    

    erstens: wie verhindere ich das er mit das wort "dir?" 5 mal ausgibt (siehe problem 10 schleifendurchläufe)? jetzt bitte nicht mit 6 statt 10 schleifendurchläufe kommen. darauf wär ich auch gekommen. die anzahl der zeilen kann sich ja in der datei ändern.
    und
    zweitens: wie ändere ich die formatierung? das jedes wort jetzt einzeln auf einer zeile steht, liegt mit sicherheit an der printf-funktion + \n. allerdings würde ohne return alles in einer zeile stehen, was ja auch logisch aber eben nicht ganz das ist, was ich will.
    wie händel ich es also, dass er mir die zwei zeilen aus der datei auch als 2 zeilen in der console ausgibt und eben nicht so wie das jetzt der fall ist?

    besten dank und gruß
    norbert


  • Mod

    Viel zu umständlich! Und im Ansatz auch schon vermurkst, wie du selber merkst. Die Aufgabe ist ziemlich trivial auf eine der folgenden Arten und Weisen zu lösen:
    -Einfach alles einlesen und ausgeben, schließlich sind die Zeilenumbrüche schon in der Datei
    -fgets benutzen
    -scanf mit negated scanset auf Zeilenumbruch benutzen ( %[^\n] )
    -Bestimmt noch viele andere

    Denk dran, dass es auch so etwas wie Rückgabewerte von Lesefunktionen gibt. So kann man einfach so lange einlesen, bis man das Ende erreicht hat, ohne dieses im Voraus zu kennen.

    Damit ist die Aufgabe ein Dreizeiler. Fünf Zeilen, wenn man sehr großzügig ist.



  • Lange Fassung, etwas erklärender:

    #include <stdio.h>  // fopen, ftell, fseek, rewind, puts, fgets, fputs, fclose, printf
    
    // Program entry
    main(){
        // Declarations
        FILE* file;
        long file_size;
        char line[255];
        // Open file (in read mode)
        file = fopen("input.txt", "r");
        if(file){   // file != NULL  ->file handle is valid and can be used
            // Get file length
            file_size = ftell(file);  // Get current file position which is the start
            fseek(file, 0, SEEK_END);   // Set file position to the end
            file_size = ftell(file) - file_size;    // Calculate file size by <end - start>
            // Output file size
            printf("File size in bytes: %ld\n", file_size);
            // Set file pointer back to start
            rewind(file);
            // Output file line-per-line
            puts("File content:");
            while(fgets(line, sizeof(line), file))   // fgets(...) != NULL  ->read line successfully
                fputs(line, stdout);
            // Close file
            fclose(file);
        }else
            puts("Couldn't open file!");
    }
    

    Oder kurz, als Zweizeiler:

    #include <stdio.h>
    main(){FILE* file = fopen("input.txt", "r"); char line[255]; while(fgets(line, sizeof(line), file)) fputs(line, stdout);}
    


  • Das printf(line) ist gefährlich und daher zu vermeiden.

    Das line ist in diesem Fall der Formatstring.
    Wenn in der Datei ein ein gültiger Formatspecifier steht, will printf auch den Paramter dazu haben und nimmst sich den auch.

    %s%s%s%s
    Hallo Welt!
    %s%s%s%s
    

    Daher

    printf("%s", line);
    


  • Oder gleich

    puts(line);
    

    (bei der Fehlermeldung hat Youka ja auch schon diese Funktion benutzt 😉



  • Th69 schrieb:

    Oder gleich

    puts(line);
    

    (bei der Fehlermeldung hat Youka ja auch schon diese Funktion benutzt 😉

    Ne, so einfach ist das nicht. 😉

    puts hängt automatisch ein '\n' an. Das steht aber noch in line vom fgets
    Dann wird es immer eine Leerzeile dazwischen geben.

    Daher dann als Gegenpart von fgets:

    fputs(line, stdout);
    

    (welches ich auch lieber nehme, da es dir richtige Funktion dafür ist)

    Allerdings optimiert der Compiler (wenn er darf) das printf("%s", von alleine durch ein fputs(
    (Und printf("%s\n", von alleine durch ein puts(

    Diese Optimierung kann er bei einem printf(line) auch nicht machen, da er den Inhalt von line nicht kennt)



  • Upps, du hast Recht. Immer diese Inkonsistenzen zwischen den verschiedenen Funktionen. 👎


Anmelden zum Antworten