Leia todo o arquivo ASCII em C ++ std :: string

Eu preciso ler um arquivo inteiro na memory e colocá-lo em um C ++ std::string .

Se eu fosse lê-lo em um char[] , a resposta seria muito simples:

 std::ifstream t; int length; t.open("file.txt"); // open input file t.seekg(0, std::ios::end); // go to the end length = t.tellg(); // report location (this is the length) t.seekg(0, std::ios::beg); // go back to the beginning buffer = new char[length]; // allocate memory for a buffer of appropriate dimension t.read(buffer, length); // read the whole file into the buffer t.close(); // close file handle // ... Do stuff with buffer here ... 

Agora, eu quero fazer exatamente a mesma coisa, mas usando um std::string vez de um char[] . Eu quero evitar loops, ou seja, eu não quero:

 std::ifstream t; t.open("file.txt"); std::string buffer; std::string line; while(t){ std::getline(t, line); // ... Append line to buffer and go on } t.close() 

Alguma ideia?

Atualização: Acontece que este método, apesar de seguir bem os idiomas STL, é surpreendentemente ineficiente! Não faça isso com arquivos grandes. (Veja: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html )

Você pode fazer um iterador streambuf fora do arquivo e inicializar a string com ele:

 #include  #include  #include  std::ifstream t("file.txt"); std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); 

Não tenho certeza de onde você está obtendo a t.open("file.txt", "r") de. Tanto quanto eu sei que não é um método que std::ifstream tem. Parece que você confundiu com o fopen de C.

Edit: Observe também os parênteses extras ao redor do primeiro argumento para o construtor de string. Estes são essenciais . Eles evitam o problema conhecido como “a mais difícil “, que neste caso não lhe dará um erro de compilation como normalmente acontece, mas lhe dará resultados interessantes (leia-se: errado).

Seguindo o ponto de KeithB nos comentários, aqui está uma maneira de fazer isso que aloca toda a memory na frente (ao invés de confiar na realocação automática da class de string):

 #include  #include  #include  std::ifstream t("file.txt"); std::string str; t.seekg(0, std::ios::end); str.reserve(t.tellg()); t.seekg(0, std::ios::beg); str.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); 

Existem algumas possibilidades. Eu gosto de usar um stringstream como intermediário:

 std::ifstream t("file.txt"); std::stringstream buffer; buffer << t.rdbuf(); 

Agora o conteúdo de "file.txt" está disponível em uma string como buffer.str() .

Outra possibilidade (embora eu certamente não goste também) é muito mais parecida com o seu original:

 std::ifstream t("file.txt"); t.seekg(0, std::ios::end); size_t size = t.tellg(); std::string buffer(size, ' '); t.seekg(0); t.read(&buffer[0], size); 

Oficialmente, isso não é necessário para trabalhar com o padrão C ++ 98 ou 03 (a string não é necessária para armazenar dados de forma contígua), mas na verdade funciona com todas as implementações conhecidas, e o C ++ 11 e posterior requerem armazenamento contíguo , então é garantido que funcione com eles.

Quanto ao porquê eu não gosto do último também: primeiro, porque é mais longo e mais difícil de ler. Segundo, porque requer que você inicialize o conteúdo da string com dados que não se importam, então imediatamente escreva sobre esses dados (sim, o tempo para inicializar é geralmente trivial comparado com a leitura, então provavelmente não importa , mas para mim ainda parece meio errado). Terceiro, em um arquivo de texto, a posição X no arquivo não significa necessariamente que você tenha lido caracteres X para alcançar esse ponto - não é necessário levar em conta coisas como traduções de fim de linha. Em sistemas reais que fazem tais traduções (por exemplo, Windows) o formato traduzido é menor do que o que está no arquivo (ou seja, "\ r \ n" no arquivo torna-se "\ n" na string traduzida) então tudo que você fez é reservado um pouco de espaço extra que você nunca usa. Novamente, não causa um grande problema, mas parece um pouco errado.

Eu acho que a melhor maneira é usar o stream de strings. Simples e rápido !!!

 ifstream inFile; inFile.open(inFileName);//open the input file stringstream strStream; strStream << inFile.rdbuf();//read the file string str = strStream.str();//str holds the content of the file cout << str << endl;//you can do anything with the string!!! 

Você pode não encontrar isso em nenhum livro ou site, mas descobri que funciona muito bem:

 ifstream ifs ("filename.txt"); string s; getline (ifs, s, (char) ifs.eof()); 

Tente um destes dois methods:

 string get_file_string(){ std::ifstream ifs("path_to_file"); return string((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); } string get_file_string2(){ ifstream inFile; inFile.open("path_to_file");//open the input file stringstream strStream; strStream << inFile.rdbuf();//read the file return strStream.str();//str holds the content of the file } 

Eu descobri outra maneira que funciona com a maioria das trilhas, incluindo std: cin!

 std::string readFile() { stringstream str; ifstream stream("Hello_World.txt"); if(stream.is_open()) { while(stream.peek() != EOF) { str << (char) stream.get(); } stream.close(); return str.str(); } } 

Eu poderia fazer assim:

 void readfile(const std::string &filepath,std::string &buffer){ std::ifstream fin(filepath.c_str()); getline(fin, buffer, char(-1)); fin.close(); } 

Se isso é algo para ser desaprovado, por favor, deixe-me saber por que

Se acontecer de você usar o glibmm, você pode tentar o Glib :: file_get_contents .

 #include  #include  int main() { auto filename = "my-file.txt"; try { std::string contents = Glib::file_get_contents(filename); std::cout << "File data:\n" << contents << std::endl; catch (const Glib::FileError& e) { std::cout << "Oops, an error occurred:\n" << e.what() << std::endl; } return 0; } 

Eu não acho que você pode fazer isso sem um loop explícito ou implícito, sem ler em uma matriz char (ou algum outro contêiner) primeiro e dez construindo a string. Se você não precisa dos outros resources de uma string, isso pode ser feito com o vector da mesma maneira que você está usando um char * .