2009-11-07 19 views
8

Tengo un vector grande (10^9 elementos) de caracteres, y me preguntaba cuál es la forma más rápida de escribir dicho vector en un archivo. Hasta ahora he estado usando el siguiente código:La forma más rápida de escribir un vector STL grande en un archivo usando STL

vector<char> vs; 
// ... Fill vector with data 
ofstream outfile("nanocube.txt", ios::out | ios::binary); 
ostream_iterator<char> oi(outfile, '\0'); 
copy(vs.begin(), vs.end(), oi); 

Para este código, toma aproximadamente dos minutos escribir todos los datos en el archivo. La pregunta real es: "¿Puedo hacerlo más rápido usando STL y cómo"?

+0

¿Hay algún otro procesamiento que desee realizar mientras la escritura se realiza en segundo plano? Si es así, use E/S superpuesto pasando vs.data() como el buffer y vs.size() como el número de bytes que se escribirá según lo especificado por Charles Salvia. – Modicom

Respuesta

3

Hay un ligero error conceptual con su segundo argumento al constructor de ostream_iterator. Debería ser un puntero NULL, si no desea un delimitador (aunque, afortunadamente para usted, esto se tratará como tal implícitamente), o el segundo argumento debe omitirse.

Sin embargo, esto significa que después de escribir cada carácter, el código debe verificar el puntero que designa el delimitador (que podría ser algo ineficaz).

Creo que si quieres ir con iteradores, quizás puedas probar ostreambuf_iterator.

Otras opciones pueden incluir el uso del método write() (si puede manejar un resultado tan grande, o tal vez generarlo en fragmentos) y quizás funciones de salida específicas del sistema operativo.

+1

Acabo de leer la sección en "Effective STL" de Meyer que menciona las clases '[io] streambuf_iterator'. Perfecto para esto – Tom

+0

Thnx para la corrección. Copié la pasta de algún lugar sin una visión más profunda. – ljubak

+0

Olvidé decir que estoy tratando de hacer que las cosas sean independientes de la plataforma, por lo que el sistema operativo específico está fuera de cuestión, pero de nuevo. – ljubak

-1

Utiliza el método de escritura en él, está en RAM después de todo y tienes memoria contigua ... ¿Más rápido, mientras buscas flexibilidad más adelante? Pierde el búfer incorporado, sugiere secuencia de E/S, pierde las cosas ocultas de iterador/utilidad, evite streambuf cuando pueda pero ensucie con boost :: asio ..

21

Con una gran cantidad de datos en escrito (~ 1GB), debe escribir en la secuencia de salida directamente, en lugar de usar un iterador de salida. Como los datos en un vector se almacenan contiguamente, esto funcionará y debería ser mucho más rápido.

ofstream outfile("nanocube.txt", ios::out | ios::binary); 
outfile.write(&vs[0], vs.size()); 
+0

Me preguntaba por qué 'outfile.write (reinterpret_cast (& (vs)), vs.size() * sizeof (T));' no funciona? – Javier

2

Dado que los datos están contiguos en la memoria (como dijo Charles), puede utilizar E/S de bajo nivel. En Unix o Linux, puede escribir en un descriptor de archivo. En Windows XP, use manejadores de archivos. (Es un poco más complicado en XP, pero está bien documentado en MSDN.)

XP es un poco divertido sobre el almacenamiento en búfer. Si escribe un bloque de 1 GB en un controlador, será más lento que si divide la escritura en tamaños de transferencia más pequeños (en un bucle). Descubrí que las escrituras de 256 KB son más eficientes. Una vez que haya escrito el ciclo, puede jugar con esto y ver cuál es el tamaño de transferencia más rápido.

1

OK, escribí la implementación del método con for loop que escribe bloques de 256 KB (como Rob sugirió) de los datos en cada iteración y el resultado es 16 segundos, por lo que resuelve el problema. Esta es mi humilde implementación así que no dude en comentar:

void writeCubeToFile(const vector<char> &vs) 
{ 
    const unsigned int blocksize = 262144; 
    unsigned long blocks = distance(vs.begin(), vs.end())/blocksize; 

    ofstream outfile("nanocube.txt", ios::out | ios::binary); 

    for(unsigned long i = 0; i <= blocks; i++) 
    { 
     unsigned long position = blocksize * i; 

     if(blocksize > distance(vs.begin() + position, vs.end())) outfile.write(&*(vs.begin() + position), distance(vs.begin() + position, vs.end())); 
     else outfile.write(&*(vs.begin() + position), blocksize); 
    } 

    outfile.write("\0", 1); 

    outfile.close(); 
} 

Thnx a todos ustedes.

1

Si tiene otra estructura, este método sigue siendo válido.

Por ejemplo:

typedef std::pair<int,int> STL_Edge; 
vector<STL_Edge> v; 

void write_file(const char * path){ 
    ofstream outfile(path, ios::out | ios::binary); 
    outfile.write((const char *)&v.front(), v.size()*sizeof(STL_Edge)); 
} 

void read_file(const char * path,int reserveSpaceForEntries){ 
    ifstream infile(path, ios::in | ios::binary); 
    v.resize(reserveSpaceForEntries); 
    infile.read((char *)&v.front(), v.size()*sizeof(STL_Edge)); 
} 
1

En lugar de escribir a través del archivo i/métodos O, usted podría tratar de crear un archivo asignado en memoria, y luego copiar el vector al archivo asignado en memoria utilizando memcpy.

Cuestiones relacionadas