stdin binär einlesen

  • Hallo zusammen!


    Ich wollte mal ein kleines Tool unter Linux programmieren, das sich eigentlich ganz simpel anhört. Ich wollte die Standard-Eingabe einlesen und in evtl. veränderter Form wieder auf der Standard-Ausgabe ausgeben.


    Das ganze soll so funktionieren, dass ich also irgendeine Ausgabe in das Tool pipen kann und dann die veränderte Ausgabe von dem Tool erhalte.


    Bei meinen Versuchen mit cin und cin.get / cin.read gelang es mir nicht, zu erkennen, wann keine Eingabe mehr vorliegt. Kann man das beim Piping ordentlich erkennen? Desweiteren hatte ich das Problem, dass immer auf die Eingabe-Taste gewartet wurde.


    Kann es sein, dass man den stdin für meine Zwecke in einen Binär-Modus schalten muss?


    Gruß,
    Bienchen :)

  • Zitat

    Original von bienchen
    Bei meinen Versuchen mit cin und cin.get / cin.read gelang es mir nicht, zu erkennen, wann keine Eingabe mehr vorliegt. Kann man das beim Piping ordentlich erkennen?


    Haste sowas auch schon probiert?


    Code
    while ( !cin.eof() ){
         char c;
         while( cin >> c ) cout << c;
      }


    Müsste

  • Zitat

    Original von bienchen
    Bei meinen Versuchen mit cin und cin.get / cin.read gelang es mir nicht, zu erkennen, wann keine Eingabe mehr vorliegt. Kann man das beim Piping ordentlich erkennen?


    Naja, du kannst erkennen, wenn ein EOF in die Pipe geschrieben wird, oder wenn die Pipe "bricht", also der schreibende Prozess einfach beendet wird. Wenn der Sender einfach nicht mehr sendet kannst du das wohl nur über Timeouts erkennen.


    Zitat

    Desweiteren hatte ich das Problem, dass immer auf die Eingabe-Taste gewartet wurde.


    Kann es sein, dass man den stdin für meine Zwecke in einen Binär-Modus schalten muss?


    stdin hat keine "modi". Dein Problem ist, dass du mit stream inserters und extractors auf std::cin und std::cout arbeitest. Die sind (wie immer wieder gerne zitiert wird) für formatierte Ein- und Ausgabe. Tauch doch mal ein bisschen ein in die Tiefen der STL und schau dir insbesondere die template-klassen basic_streambuf<> und char_traits<> an, dann siehst du, dass da hinter den Kulissen jede Menge "magic" passiert :)


    Für deine Zwecke wäre es wohl am einfachsten, stdin direkt zu verwenden, mit ein paar Funktionen der guten alten C-Standardlib (fread, select und ähnliche).


    Ich hätte hier noch einen bidirektionalen Pipe-Stream ;) http://palmen.homeip.net/svn/w…wapp/libwapp/pipestream.h allerdings forkt der auch gleich das Programm, mit dem dann Daten ausgetauscht werden sollen.

    Asrock A75 Pro4-M
    Debian wheezy (testing, stock) (aktuell 2012-08-24: Linux 3.2, VDR 1.7.28)
    vdr-sxfe (xineliboutput)
    Pioneer VSX-520-K

  • @Ioannis: nicht in der Form, habs aber jetzt gerade mal ausprobiert... klappte auch nicht... das gleiche Problem.


    zirias: Interessant wäre es, zu erkennen, wann die Pipe bricht. Ich komme von der Windows-Programmierung (C#, Delphi) und habe da wahrscheinlich erstmal Probleme, mich mit den anderen Strukturen von Linux vertraut zu machen. Unter DOS war damals ein #26 ein EOF-Signal. Wäre das unter Linux ähnlich? Wenn ja, kann ich das nicht brauchen. Ich möchte gerne Binär-Ströme durchleiten und bearbeiten. Daher wäre es eigentlich nur notwendig, das Brechen der Pipe zu erkennen.


    Mit dem tiefer Eintauchen würde ich als C++/Linux-Noob lieber erstmal vor mir her schieben. Eigentlich dachte ich, dass dieses einfache Problem prima für einen Einstieg mit Erfolgserlebnis geeignet wäre ;)


    Allerdings wäre es interessant, ein wenig mehr über die direkte Verwendung von stdin zu erfahren. Ich habe mir mal die cc-Datei hinter deinem Link anschaut, werde daraus aber nicht wirklich schlau. Könntest Du vielleicht ein einfaches Beispiel mit fread/fwrite angeben?


    Gruß,
    Bienchen :)


    PS: Ich vermisse eine gute Referenz der Klassen (und natürlich Auto-Completion ;-)). Gibt es für Linux evtl. eine Online-Referenz?

  • Hallo zusammen!


    Dank der Tips hier, konnte ich Beispiele finden!


    Code
    char c;
        int i;
        i = fread(&c, 1, 1, stdin);
        while(i > 0) {
            fwrite(&c, 1, 1, stdout);
            i = fread(&c, 1, 1, stdin);
        }
        return 0;


    Das tut genau das, was ich gesucht habe. Damit kann ich exakt das wieder rausbekommen, was rein ging (es gehen keine Zeilenumbrüche verloren).


    Dass ich dachte, ich würde broken Pipes nicht erkennen, lag daran, dass ich falsch gepipt hatte.


    Aber wenn ihr bzgl. meiner restlichen Fragen noch Tipps für mich habt, wäre ich sehr dankbar :)


    Gruß,
    Bienchen :)

  • Hier nochmal ein C++-analoges Beispiel ;)


    (cin und cout machen nicht nur formatierte Ein-/Ausgabe)


    Code
    while (cin) {
            char c;
            cin.read(&c, 1);
            if (cin.gcount() > 0)
                cout.write(&c, 1);
        }
    
    
        if (!cin.eof())
            cerr << "Lesefehler" << endl;


    Oder blockweise (Fehlerbehandlung analog):

    Code
    while (cin) {
            char buf[8192];
            cin.read(buf, sizeof buf);
            cout.write(buf, cin.gcount()); // cin.gcount() sollte immer, bis auf beim letzten Durchgang, 8192 enthalten
        }
    
    
        if (!cin.eof())
            cerr << "Lesefehler" << endl;
  • Zitat

    Original von LordJaxom
    Hier nochmal ein C++-analoges Beispiel ;)


    (cin und cout machen nicht nur formatierte Ein-/Ausgabe)


    Richtig, das machen << und >>, aber cin/cout sind primär dafür gedacht. Was alle Streams machen ist jedenfalls die Behandlung mit einer traits-Klasse, normalerweise char_traits<char>. Üblicherweise macht die nur ein 1:1 Mapping zwischen char und int, das könnte aber auf Platformen mit eigenwilliger Text-Codierung durchaus auch mal anders sein.


    Meistens will man natürlich genau diesen Mechanismus haben, manchmal aber eben auch nicht (wenn es um binary Daten geht). Ich hab jetzt bim kurzem googlen Hinweise auf einen Stream-Modifier ios::binary gefunden, vielleicht schaltet der eventuelle Übersetzungen durch traits-Klassen ab, bin mir da aber gerade nicht sicher ;)

    Asrock A75 Pro4-M
    Debian wheezy (testing, stock) (aktuell 2012-08-24: Linux 3.2, VDR 1.7.28)
    vdr-sxfe (xineliboutput)
    Pioneer VSX-520-K

  • Zitat

    Original von zirias
    Richtig, das machen << und >>, aber cin/cout sind primär dafür gedacht. Was alle Streams machen ist jedenfalls die Behandlung mit einer traits-Klasse, normalerweise char_traits<char>. Üblicherweise macht die nur ein 1:1 Mapping zwischen char und int, das könnte aber auf Platformen mit eigenwilliger Text-Codierung durchaus auch mal anders sein.


    Meistens will man natürlich genau diesen Mechanismus haben, manchmal aber eben auch nicht (wenn es um binary Daten geht). Ich hab jetzt bim kurzem googlen Hinweise auf einen Stream-Modifier ios::binary gefunden, vielleicht schaltet der eventuelle Übersetzungen durch traits-Klassen ab, bin mir da aber gerade nicht sicher ;)


    Beim blockweisen Lesen mit read(some)/write werden soweit ich weiss im Textmodus ohnehin nur noch Line-Endings gewandelt (per widen/narrow). Locale-spezifische Sachen werden bei der formatierten Ausgabe benutzt. Aber ja, ios::binary als Flag beim Open sollte auf jedenfall dafür sorgen, dass die Daten unverändert ankommen. Bei der formatierten Ausgabe hingegen hat ios::binary widerum keinen Effekt, wenn ich dann cin << int(0x0a) mache landet eine formatierte "10" in der Ausgabe, kein Linefeed.


    EDIT:
    Aber weil es angesprochen wurde, hier nochmal die Variante mit streambuf_iteratoren :D

    Code
    copy(istreambuf_iterator<char>(cin), istreambuf_iterator<char>(), ostreambuf_iterator<char>(cout));

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!