2010-01-18 9 views
8

Ok, aquí hay un código que describe lo que estoy tratando de hacer.Copia de una transmisión estándar a otra de manera eficiente

#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; 
      } 
     } 
    } 
} 

Primero lee grandes cantidades de datos en un búfer de datos. Sé que hay mejores formas C++ de hacer esta parte, pero en mi aplicación real me entregan un búfer char [] y una longitud.

Escribo el búfer en un objeto std :: stringstream para poder eliminar una línea a la vez.

Pensé que usaría el método get (streambuf &) en el flujo de cadenas para escribir una línea en otra secuencia de cadenas donde luego puedo generarla.

Ignorando el hecho de que esta puede no ser la mejor forma de extraer una línea a la vez del buffer que leí (aunque me gustaría que alguien ofrezca una mejor alternativa a la que publico aquí) , tan pronto como se llame al primer , el ss está en un estado de falla y no sé por qué. Hay una gran cantidad de datos en el archivo de entrada para que ss contenga definitivamente más de una línea de entrada.

¿Alguna idea?

Respuesta

0

He probado esto en Windows, por lo que es posible que desee verificar esto;

Si el data.out comienza con una nueva línea, me sale el mismo problema que tiene, de lo contrario, el ss.get (* s2.rdbuf()) funciona bien para la primera llamada.

Cuando se invoca por segunda vez, la posición actual de la secuencia no ha avanzado más allá de la EOL. Entonces, cuando se llama por segunda vez, inmediatamente intenta leer el EOL y, como no se han copiado otros caracteres, establece el bit de falla.

rápida y tal vez sucia solución:

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

Me parece que el primer paso (y probablemente más importante) para obtener la eficiencia decente es reducir al mínimo la copia de los datos. Como se te están dando los datos en un char [] con una longitud, mi primera tendencia sería comenzar creando un strstream usando ese buffer. Luego, en lugar de copiar una cadena a la vez en otra secuencia (o secuencia de cadenas), copie las cadenas de una en una a la secuencia que utilizará para escribirlas en la salida.

Si tiene permiso para modificar el contenido del búfer, otra posibilidad sería analizar el búfer en líneas simplemente reemplazando cada '\ n' con un '\ 0'. Si va a hacer eso, normalmente querrá crear un vector (deque, etc.) de punteros al principio de cada línea (es decir, encuentre el primero '\ r' o '\ n', y reemplázalo con un '\ 0'. Luego, la siguiente cosa que no sea '\ r' o '\ n' es el comienzo de la siguiente línea, entonces su dirección en su vector).

También pensaría mucho acerca de si puede evitar la salida de línea por vez. Leer a través de un gran buffer para encontrar nuevas líneas es relativamente lento. Si va a terminar escribiendo una línea después de otra de todos modos, puede evitar todo esto simplemente escribiendo en todo el búfer en el flujo de salida y terminando con eso.

Cuestiones relacionadas