Читать весь ASCII файл на С++ std::string

Мне нужно прочитать целый файл в памяти и поместить его в С++ 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()

Любые идеи?

Ответ 1

Обновление:. Оказывается, этот метод, хорошо соблюдая идиомы 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. Похоже, вы смутили его с помощью C 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>());

Ответ 2

Есть несколько возможностей. Тот, который мне нравится, использует поток строк в качестве посредника:

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); 

Официально это не требуется для работы в соответствии со стандартом С++ 98 или 03 (строка не требуется для непрерывного хранения данных), но на самом деле она работает со всеми известными реализациями, и С++ 11 и более поздние версии требуется непрерывное хранение, поэтому он гарантированно будет работать с ними.

Что касается того, почему мне не нравятся и последние: во-первых, потому что они длиннее и сложнее для чтения. Во-вторых, поскольку требуется инициализировать содержимое строки данными, которые вам не нужны, а затем немедленно записать эти данные (да, время инициализации обычно тривиально по сравнению с чтением, поэтому, вероятно, это не имеет значения, но мне все еще кажется, что это неправильно). В-третьих, в текстовом файле положение X в этом файле не обязательно означает, что вы прочитали символы X, чтобы достичь этой точки - необязательно принимать во внимание такие вещи, как переводы в конце строки. В реальных системах, которые выполняют такие переводы (например, в Windows), переведенная форма короче, чем в файле (т.е. "\ R\n" в файле становится "\n" в переведенной строке), поэтому все, что вы сделали зарезервировано немного дополнительного пространства, которое вы никогда не используете. Опять же, на самом деле не вызывает серьезных проблем, но все равно чувствует себя немного не так.

Ответ 3

Я думаю, что лучший способ - использовать поток строк. просто и быстро !!!

#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream
int main() {
    std::ifstream inFile;
    inFile.open("inFileName"); //open the input file

    std::stringstream strStream;
    strStream << inFile.rdbuf(); //read the file
    std::string str = strStream.str(); //str holds the content of the file

    std::cout << str << "\n"; //you can do anything with the string!!!
}

Ответ 4

Вы не можете найти это в любой книге или на сайте, но я узнал, что он работает очень хорошо:

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

Ответ 5

Попробуйте один из этих двух методов:

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
}

Ответ 6

Я нашел другой способ, который работает с большинством потоков 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();
    }
}

Ответ 7

Если вы используете 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;
}

Ответ 8

Я мог бы сделать это вот так:

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

Если это что-то, на что можно не согласиться, пожалуйста, сообщите мне, почему

Ответ 9

Я не думаю, что вы можете сделать это без явного или неявного цикла, не прочитав сначала массив char (или какой-либо другой контейнер) и десять построив строку. Если вам не нужны другие возможности строки, это можно сделать с помощью vector<char> так же, как вы в настоящее время используете char *.