Pergunta

A fim de melhorar a leitura desempenho de um arquivo, eu estou tentando ler todo o conteúdo de um grande (vários MB) de arquivos na memória e, em seguida, usar um istringstream para acessar as informações.

A minha pergunta é, qual é a melhor maneira de ler esta informação e "importação-lo" no fluxo de corda? Um problema com esta abordagem (ver abaixo) é que ao criar o fluxo de corda os buffers é copiado, e duplos de uso de memória.

#include <fstream>
#include <sstream>

using namespace std;

int main() {
  ifstream is;
  is.open (sFilename.c_str(), ios::binary );

  // get length of file:
  is.seekg (0, std::ios::end);
  long length = is.tellg();
  is.seekg (0, std::ios::beg);

  // allocate memory:
  char *buffer = new char [length];

  // read data as a block:
  is.read (buffer,length);

  // create string stream of memory contents
  // NOTE: this ends up copying the buffer!!!
  istringstream iss( string( buffer ) );

  // delete temporary buffer
  delete [] buffer;

  // close filestream
  is.close();

  /* ==================================
   * Use iss to access data
   */

}
Foi útil?

Solução

std::ifstream tem uma rdbuf() método, que retorna um ponteiro para uma filebuf. Você pode, então, "push" este filebuf em seu stringstream:

#include <fstream>
#include <sstream>

int main()
{
    std::ifstream file( "myFile" );

    if ( file )
    {
        std::stringstream buffer;

        buffer << file.rdbuf();

        file.close();

        // operations on the buffer...
    }
}

EDIT: Como Martin Iorque observa nos comentários, isso pode não ser a solução mais rápida desde stringstream do operator<< vai ler o caráter filebuf pelo caráter. Você pode querer verificar sua resposta, onde ele usa o método ifstream do read como você costumava fazer, e, em seguida, definir o tampão stringstream para apontar para a memória alocada anteriormente.

Outras dicas

OK. Não estou dizendo que isso vai ser mais rápido do que a leitura do arquivo

Mas este é um método onde você cria o buffer de uma vez e depois os dados são lidos para o uso de tampão-lo diretamente como fonte para stringstream.

NB. Vale a pena mencionar que o std :: ifstream é tamponado. Ele lê os dados do arquivo em (relativamente grandes) blocos. operações de fluxo são realizadas contra o tampão retornando apenas para o arquivo para uma outra leitura quando mais dados são necessários. Então, antes de sugar todos os dados na memória por favor verificar que este é um gargalo de garrafa.

#include <fstream>
#include <sstream>
#include <vector>

int main()
{
    std::ifstream       file("Plop");
    if (file)
    {
        /*
         * Get the size of the file
         */
        file.seekg(0,std::ios::end);
        std::streampos          length = file.tellg();
        file.seekg(0,std::ios::beg);

        /*
         * Use a vector as the buffer.
         * It is exception safe and will be tidied up correctly.
         * This constructor creates a buffer of the correct length.
         *
         * Then read the whole file into the buffer.
         */
        std::vector<char>       buffer(length);
        file.read(&buffer[0],length);

        /*
         * Create your string stream.
         * Get the stringbuffer from the stream and set the vector as it source.
         */
        std::stringstream       localStream;
        localStream.rdbuf()->pubsetbuf(&buffer[0],length);

        /*
         * Note the buffer is NOT copied, if it goes out of scope
         * the stream will be reading from released memory.
         */
    }
}

Esta parece ser otimização prematura para mim. Quanto trabalho está sendo feito no processamento. Assumindo um desktop / servidor modernish, e não um sistema embarcado, copiando alguns MB de dados durante intialization é bastante barato, especialmente em comparação com a leitura do arquivo fora do disco em primeiro lugar. Gostaria de ficar com o que você tem, medir o sistema quando ele estiver concluída, ea decidir se os potenciais ganhos de desempenho seria pena. Claro, se a memória é pequena, isto é, em um loop interno, ou um programa que é chamado muitas vezes (como uma vez por segundo), que altera o equilíbrio.

Outra coisa a ter em mente é que arquivo de I / O é sempre vai ser a operação mais lenta. A solução de Luc Touraille é correto, mas existem outras opções. Lendo o arquivo inteiro na memória de uma vez será muito mais rápido do que em separado lê.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top