eine bestimmte Zeile aus einer Textdatei ausgeben



  • Hallo,

    Ich habe vor ein par Wochen mit C angefangen, daher weiß ich nur wenig über Befehle oder auch die Möglichkeiten in C. Hoffe Ihr könnt mir aber trotzdem helfen.
    Ich möchte von meinem Shoutcastserver den Onlinestatus durch die xml Datei auswerten. Dort gibt es eine Zeile die mir den Onlinestatus mitteilt. <UPDINFO>0</UPDINFO>. Wenn ich eine Audiosource zum Server verbinde, ändert sich die 0 auf 1. Wenn das der fall ist, möchte ich damit gern im cmd oder console, je nach Betriebssystem, eine Programm mit Parametern starten....bei 0 oder auch wenn die Datei nicht gefunden werden kann, soll das Ausgeführte Programm gestopt werden... soweit meine Vorstellung von meinem kleinen Projekt 🙂

    hier erstmal der bisher geschriebene Source Code.

    void main (void)
    
    {
    	int ch;
    	FILE *stream;
    	char dateiname[800];
    	stream = fopen("test.txt","r");
    	if(stream != NULL)
    		{
    			printf("\nDatei konnte geöffnet werden \n");
    		}
    	else
    		{
    			printf("\nDatei konnte nicht geöffnet werden \n");
    		}
    		ch=fgetc(stream);
    		while(!feof(stream))
    		{
    			putchar(ch);
    			ch=fgetc(stream);
    		}
    		fclose(stream);
    }
    

    zum testen hab ich den Inhalt der xml Datei in die TXT kopiert. Bisher funktioniert auch die Ausgabe der kompletten Textdatei.

    Mein Problem besteht darin, das ich den Startpunkt des zulesenden Textes ändern möchte, da ich ja nur <UPDINFO>0</UPDINFO> brauch, der auch immer in der selben Zeile steht. Mit char dateiname[20] wollt ich dann die Länge begrenzen. Falls dann ch = <UPDINFO>1</UPDINFO> --> Program ausführen.

    Ist der Gedankengang bis hierhin richtig? oder würdet ihr einen ganz anderen Lösungsweg wählen?

    vielen Dank schonmal.

    gruß base



  • Wenn diese Zeile immer an der selben Position (bytegenau) in der Datei steht, kannst du dir die Position merken und per fseek() anspringen, bevor du zu Lesen beginnst.
    Wenn sich die Länge oder die Anordnung der anderen XML-Einträge ändern kann, mußt du die Datei wohl zeilenweise mit fgets() einlesen und jede Zeile per strcmp() oder memcmp() mit "<UPINFO>" vergleichen.



  • Danke für die schnelle Antwort.
    Werde mich wohl noch ein par Tage einlesen müssen. Auf die schnelle krieg ich die Syntax nicht hin...



  • Man sollte sich im Allgemeinen nicht damit plagen, einen XML-Parser zu schreiben...

    Wenn's doch sein muss, dann so, wie CStoll sagte:

    #include <string.h>
    #include <stdio.h>
    
    #define STAG "<UPINFO>"
    #define ETAG "</UPINFO>"
    #define BUFSIZ 512
    
    int main() 
    {
        char linebuf[BUFSIZ];
        int start, end;
        FILE *stream;
    
        stream = fopen(...);
        /* Fehlerbehandlung ausgespart */
    
        while (fgets(stream, linebuf))
            if (start = strstr(linebuf, STAG) &&
                    end = strstr(linebuf, ETAG)) {
                *end = '\0';
                puts("Zwischen den Tags steht: ");
                puts(start + strlen(STAG));
        }
        fclose(stream);
        return 0;
    }
    

    wobei auch hier Einschränkungen gelten:
    * Start und Endtag müssen in einer Zeile stehen
    * Start und Endtag müssen in Grossbuchstaben geschrieben sein.
    * Zeilen, die länger als BUFSIZ sind, werden behandelt, als wären sie's nicht

    Ich hoffe, dass dir klar ist, dass dieser Einsatzzweck nicht unbedingt nach C schreit; eher nach einer Glue-Language wie Perl, Python und was die Hexenküche noch dergleichen hergibt. Dort würdest du einfach nach dem regulären Ausdruck "<UPINFO>\S+</UPINFO>" suchen...



  • danke cheopz für die fast fertige syntax.

    hab sie ein weing angepasst und nun sieht sie so aus

    #include <string.h>
    #include <stdio.h>
    
    #define STAG "<UPINFO>"
    #define ETAG "</UPINFO>"
    #define BUFSIZ 512
    
    int main()
    
    {
        char linebuf[BUFSIZ];
        int start;
        int end;
        FILE *stream;
        stream = fopen("test.txt","r");
        if(stream != NULL)
            {
                printf("\nDatei konnte geöffnet werden \n");
            }
        else
            {
                printf("\nDatei konnte nicht geöffnet werden \n");
            }
    
        while (fgets(linebuf, start, stream))
        if (start = strstr(linebuf, STAG) &&
            end = strstr(linebuf, ETAG))
                    {
                            *end = '\0';
                	        puts("Zwischen den Tags steht: ");
                	        puts(start + strlen(STAG));
    	       	}
        fclose(stream);
    }
    

    problem ist nun, das der stringvergleich den fehler L Value required an dieser stelle rausgibt : end = strstr(linebuf, ETAG))

    angeblich spuckt der compiler den fehler raus, wenn links vom gleichheitszeichen kein integer variable definiert ist. aber end ist doch angegeben?!?

    weiß einer warum der fehler trotzdem kommt?



  • Sorry, mein Fehler: start und end sollten char* sein.
    (L-Values sind das Gegenteil zu Zeigern)
    Auch der fgets-Aufruf war Blödsinn.

    Diesmal richtig und mit Fehlerbehandlung:

    char linebuf[BUFSIZ];
        char *start, *end;
        FILE *stream;
    
        if (!(stream = fopen("test.txt", "r"))) {
            fprintf(stderr, "\nDatei konnte nicht geöffnet werden \n");
            exit(1);  /* <---- sehr wichtig, auch zu beenden, wenn's schiefgeht */
        }
    
        while (fgets(linebuf, BUFSIZ, stream))
            if ((start = strstr(linebuf, STAG)) &&
                    (end = strstr(linebuf, ETAG))) {
                *end = '\0';
                puts("Zwischen den Tags steht: ");
                puts(start + strlen(STAG));
            }
        fclose(stream);
        exit(0);
    

    Diesmal getestet.



  • hallo cheopz,

    ich hab den code gestetet, und bemerkt, das ich die stdlib noch brauche. nun läuft das programm fehlerfrei. danke soweit für deine große hilfe.

    jedoch eine sache versteh ich nicht an dem code.

    *end = '\0';
    puts("Zwischen den Tags steht: ");
    puts(start + strlen(STAG));
    

    vor *end werden ja die start bzw das ende der zeicheng gesucht.
    end sagt fgets mit dem zeichen \0 das er stopenn soll?

    welche char oder var hat denn den ausgelesenden wert enthalten?

    die puts anweisung wird nicht auf den bildschirm ausgegeben. kann das am compiler liegen? hab mal mit getch() rumgemacht, hat aber auch nicht funktioniert.

    kan mann die bufsiz in der stdio ohne weiteres erhöhen?

    danke für die mühen soweit,



  • end sagt fgets mit dem zeichen \0 das er stopenn soll?

    Nein, aber puts stoppt bei einem Nullbyte. Genauso printf und dergleichen.

    ch hab den code gestetet, und bemerkt, das ich die stdlib noch brauche.

    Glaube ich nicht, string.h und stdio.h sollten reichen.

    kan mann die bufsiz in der stdio ohne weiteres erhöhen?
    

    Vorsicht! Die Verwirrung kommt, weil ich oft die gleichen Makro-Namen wie die Bibliotheken verwende. BUFSIZ ist mein Makro, natürlich kannst du's ändern, aber nur in dieser Quelldatei. Es wird auch nur zweimal verwendet, einmal um den Puffer zu definieren, ein zweites mal für fgets(). Der Name BUFSIZ ist seit K&R in den Header-Files gebräuchlich.

    Zur Erklärung:
    Am Anfang jeder Schleife lesen wir 512 Zeichen in den Puffer linebuf (oder auch weniger, wenn die Zeile kürzer ist).
    Unser Puffer sieht dann zB so aus:

    abcdefgh<UPINFO>das_suchen_wir</UPINFO>abcdefgh...
    

    dann suchen wir darin nach den Tags, start ist danach ein Zeiger auf das erste Tag, end ein Zeiger auf das zweite Tag (wenn was gefunden wird). Das sieht dann so aus:

    abcdefgh<UPINFO>das_suchen_wir</UPINFO>abcdefgh...
    ^       ^                     ^
    linebuf start                 end
    

    (Der Name eines Arrays ist ein Zeiger auf seinen Anfang)

    Wir brauchen zur Ausgabe (für alle Biblotheksfunktionen) einen Zeiger auf ein Zeichen, von dort aus wird ausgegeben, bis '\0' kommt. Also machen wir aus dem '<' bei *end ein '\0', damit puts dort aufhören wird. Nun brauchen wir noch einen Zeiger auf das "d" von das_suchen_wir. Den erhalten wir, indem wir start um so viele Zeichen nach rechts verschieben, wie "<UPINFO>" lang ist, also ist unser Zeiger für puts: start + strlen(STAG)

    Das sieht dann so aus:

    abcdefgh<UPINFO>das_suchen_wir\0/UPINFO>abcdefgh...
                    ^             
                    start+strlen(STAG)
    

    Du wirst erkannt haben, dass die ausgelesenen Zeichen (es ist ja bei dir eh nur eines) nicht in einer eigenen Variable leben, sondern sich in den Tiefen des Puffers befinden. Wir haben ja Zeiger, um sie zu finden.

    die puts anweisung wird nicht auf den bildschirm ausgegeben. kann das am compiler liegen?

    Geht's darum:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-111042.html ?



  • Wow, hab grad ne Menge gelernt. Werde mich wohl am Wochende mal hinsetzten und den Code nochmal eigenhändig schreiben, damit der sich ein bischen vertieft... die Syntax hab ich jetzt auf jedenfall vestanden.

    Zitat:
    ich hab den code gestetet, und bemerkt, das ich die stdlib noch brauche.

    Glaube ich nicht, string.h und stdio.h sollten reichen

    Stimmt, ich habe es nochmal ausprobiert und es klapt auch ohne. Hatte wohl gestern noch Befehle drinne, die die stdlib gebraucht haben.

    Zitat:
    die puts anweisung wird nicht auf den bildschirm ausgegeben. kann das am compiler liegen?

    Geht's darum:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-111042.html ?

    Problem schon behoben. Liegt wohl irgendwie an lcc. Hab nun den Code bei einem Freund mit Borland ausprobiert und da lief er ohne Probleme. Er meinte, DEV C seih noch ein einfacher guter Compiler. - Komme aber erst morgen dazu ihn zu testen.
    Zum Problem:
    Die CMD blieb offen. Es wurde nur kein Text mit puts oder auch fprint ausgegeben,... warum auch immer.



  • DEV C ... compiler

    Der heißt GCC.
    Sehr zu empfehlen.


Anmelden zum Antworten