Прочитать весь файл ASCII в C++ std::string
Мне нужно прочитать весь файл в память и поместить его в C++ std::string
,
Если бы я должен был прочитать это в char[]
ответ был бы очень прост:
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 ...
Теперь я хочу сделать то же самое, но используя std::string
вместо char[]
, Я хочу избежать петель, то есть я не хочу:
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()
Есть идеи?
9 ответов
Обновление: оказывается, что этот метод, хотя он хорошо следует идиомам STL, на самом деле удивительно неэффективен! Не делайте этого с большими файлами. (См.: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html)
Вы можете сделать итератор streambuf из файла и инициализировать строку с ним:
#include <string>
#include <fstream>
#include <streambuf>
std::ifstream t("file.txt");
std::string str((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
Не уверен, где вы получаете t.open("file.txt", "r")
Синтаксис от. Насколько я знаю, это не метод, который std::ifstream
есть. Похоже, вы перепутали это с Си fopen
,
Редактировать: Также обратите внимание на дополнительные скобки вокруг первого аргумента в конструкторе строк. Это важно. Они предотвращают проблему, известную как " самый неприятный синтаксический анализ", которая в данном случае фактически не даст вам ошибки компиляции, как это обычно бывает, но даст вам интересные (читай: неправильные) результаты.
Следуя пункту KeithB в комментариях, вот способ сделать это, который выделяет всю память заранее (вместо того, чтобы полагаться на автоматическое перераспределение строкового класса):
#include <string>
#include <fstream>
#include <streambuf>
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<char>(t)),
std::istreambuf_iterator<char>());
Есть несколько возможностей. Мне нравится использовать струнный поток в качестве посредника:
std::ifstream t("file.txt");
std::stringstream buffer;
buffer << t.rdbuf();
Теперь содержимое файла "file.txt" доступно в виде строки buffer.str()
,
Еще одна возможность (хотя мне, конечно, она тоже не нравится) намного больше похожа на вашу оригинальную:
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);
Официально это не требуется для работы в соответствии со стандартом C++98 или 03 (строка не требуется для непрерывного хранения данных), но на самом деле она работает со всеми известными реализациями, а C++11 и более поздние версии требуют непрерывного хранения так что с ними гарантированно работать.
Что касается того, почему мне не нравятся и последние: во-первых, потому что они длиннее и сложнее для чтения. Во-вторых, поскольку требуется инициализировать содержимое строки данными, которые вам не нужны, а затем немедленно записать эти данные (да, время инициализации обычно тривиально по сравнению с чтением, поэтому, вероятно, это не имеет значения, но мне все еще кажется, что это неправильно). В-третьих, в текстовом файле положение X в этом файле не обязательно означает, что вы прочитали символы X, чтобы достичь этой точки - не обязательно принимать во внимание такие вещи, как перевод строки. В реальных системах, которые выполняют такие переводы (например, Windows), переведенная форма короче, чем то, что находится в файле (т. Е. "\ R \n" в файле становится "\n" в переведенной строке), поэтому все, что вы сделали зарезервировано немного дополнительного пространства, которое вы никогда не используете. Опять же, на самом деле не вызывает серьезных проблем, но все равно чувствует себя немного не так.
Я думаю, что лучший способ - использовать поток строк. просто и быстро!!!
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!!!
Вы можете не найти это ни в одной книге или на сайте, но я обнаружил, что это работает довольно хорошо:
ifstream ifs ("filename.txt");
string s;
getline (ifs, s, (char) ifs.eof());
Попробуйте один из этих двух методов:
string get_file_string(){
std::ifstream ifs("path_to_file");
return string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
}
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
}
Я нашел другой способ, который работает с большинством потоков istream, включая 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();
}
}
Если вы используете glibmm, вы можете попробовать Glib:: file_get_contents.
#include <iostream>
#include <glibmm.h>
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;
}
Я мог бы сделать это так:
void readfile(const std::string &filepath,std::string &buffer){
std::ifstream fin(filepath.c_str());
getline(fin, buffer, char(-1));
fin.close();
}
Если это что-то, на что нужно нахмуриться, пожалуйста, дайте мне знать, почему
Я не думаю, что вы можете сделать это без явного или неявного цикла, без чтения в массив символов (или некоторый другой контейнер) сначала и десять строящих строку. Если вам не нужны другие возможности строки, это можно сделать с помощью vector<char>
так же, как вы используете char *
,