2010-01-18 11 views
8

Ok, hier ist ein Code, der skizziert, was ich versuche zu tun.Einen STD-Stream effizient in einen anderen kopieren

#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/fcntl.h> 

#include <iostream> 
#include <sstream> 

int main(int c, char *v[]) 
{ 
    int fd = open("data.out", O_RDONLY | O_NONBLOCK); 
    std::cout << "fd = " << fd << std::endl; 

    char buffer[ 1024000 ]; 
    ssize_t nread; 

    std::stringstream ss; 

    while(true) 
    { 
     if ((nread = read(fd, buffer, sizeof(buffer) - 1)) < 0) 
      break; 

     ss.write(buffer, nread); 

     while(true) 
     { 
      std::stringstream s2; 

      std::cout << "pre-get : " << 
       (((ss.rdstate() & std::ios::badbit) == std::ios::badbit) ? "bad" : "") << " " << 
       (((ss.rdstate() & std::ios::eofbit) == std::ios::eofbit) ? "eof" : "") << " " << 
       (((ss.rdstate() & std::ios::failbit) == std::ios::failbit) ? "fail" : "") << " " << 
       std::endl; 

      ss.get(*s2.rdbuf()); 

      std::cout << "post-get : " << 
       (((ss.rdstate() & std::ios::badbit) == std::ios::badbit) ? "bad" : "") << " " << 
       (((ss.rdstate() & std::ios::eofbit) == std::ios::eofbit) ? "eof" : "") << " " << 
       (((ss.rdstate() & std::ios::failbit) == std::ios::failbit) ? "fail" : "") << " " << 
       std::endl; 

      unsigned int linelen = ss.gcount() - 1; 

      if (ss.eof()) 
      { 
       ss.str(s2.str()); 
       break; 
      } 
      else if (ss.fail()) 
      { 
       ss.str(""); 
       break; 
      } 
      else 
      { 
       std::cout << s2.str() << std::endl; 
      } 
     } 
    } 
} 

Zuerst liest es große Datenblöcke in einen Datenpuffer. Ich weiß, es gibt bessere C++ - Möglichkeiten, diesen Teil zu machen, aber in meiner realen Anwendung bekomme ich einen char [] -Puffer und eine Länge.

Ich schreibe dann den Puffer in ein Objekt std :: stringstream, damit ich eine Zeile nach der anderen entfernen kann.

Ich dachte, ich würde die get (streambuf &) Methode auf dem stringstream verwenden, um eine Zeile in einen anderen stringstream zu schreiben, wo ich es dann ausgeben kann.

Die Tatsache ignorierend, dass dies möglicherweise nicht der beste Weg ist, um eine Zeile nach der anderen aus dem Puffer zu extrahieren, den ich gelesen habe (obwohl ich möchte, dass jemand eine bessere Alternative zu der hier geposteten anbietet) Sobald der erste aufgerufen wird, ist der ss in einem Fehlerzustand und ich kann nicht herausfinden warum. Es gibt viele Daten in der Eingabedatei, so dass ss definitiv mehr als eine Zeile der Eingabe enthalten sollte.

Irgendwelche Ideen?

Antwort

0

Ich habe dies auf Windows getestet, so dass Sie dies überprüfen möchten;

Wenn data.out mit einem Zeilenumbruch beginnt, bekomme ich das gleiche Problem, das Sie sonst haben, die ss.get (* s2.rdbuf()) funktioniert gut für den ersten Anruf.

Beim zweiten Aufruf ist die aktuelle Position des Datenstroms nicht über die EOL hinausgegangen. Wenn also das zweite Mal aufgerufen wird, versucht der Leser sofort, das EOL zu lesen, und da keine anderen Zeichen kopiert wurden, wird das Fehlerbit gesetzt.

Schnell und vielleicht schmutzig fix:

ss.get(*s2.rdbuf()); 
// Get rid of EOL (may need an extra if file contains both \r and \n) 
ss.get(); 
1

Es scheint mir, dass die erste (und wahrscheinlich größte) Schritt anständige Effizienz zu erhalten, ist das Kopieren der Daten zu minimieren. Da Ihnen die Daten in einem char [] mit einer Länge gegeben werden, wäre meine erste Tendenz, mit der Erstellung eines strstream unter Verwendung dieses Puffers zu beginnen. Dann kopiere ich Strings nacheinander in einen anderen Strstream (oder Stringstream), um sie nacheinander in den Stream zu kopieren, mit dem sie in die Ausgabe geschrieben werden.

Wenn Sie den Inhalt des Puffers ändern können, besteht eine andere Möglichkeit darin, den Puffer in Zeilen zu zerlegen, indem Sie einfach jedes '\ n' durch ein '\ 0' ersetzen. Wenn Sie das tun, werden Sie normalerweise auch einen Vektor (deque, etc.) von Zeigern am Anfang jeder Zeile erstellen wollen (zB das erste '\ r' oder '\ n' und Ersetzen Sie es durch ein '\ 0'. Dann ist das nächste Ding außer einem '\ r' oder '\ n' der Anfang der nächsten Zeile, also seine Adresse in Ihrem Vektor.

Ich würde auch darüber nachdenken, ob Sie die Zeile-um-eine-Zeit-Ausgabe vermeiden können. Durch einen großen Puffer zu lesen, um neue Zeilen zu finden, ist relativ langsam. Wenn Sie trotzdem eine Zeile nach der anderen schreiben, können Sie dies alles vermeiden, indem Sie einfach den gesamten Puffer in den Ausgabestream schreiben und damit fertig werden.

Verwandte Themen