7

Считать целый ASCII-файл в std::string в C++

6

Проблема: Чтение целого файла в std::string в C++

Я пытаюсь прочитать целый файл в память и сохранить его в переменной типа std::string в C++.

Если бы я читал файл в массив символов (char[]), решение было бы довольно простым:

std::ifstream t;
int length;
t.open("file.txt");      // открытие файла
t.seekg(0, std::ios::end);    // перемещение в конец файла
length = t.tellg();           // получение текущей позиции (это длина файла)
t.seekg(0, std::ios::beg);    // возврат в начало файла
buffer = new char[length];    // выделение памяти для буфера
t.read(buffer, length);       // чтение всего файла в буфер
t.close();                    // закрытие файла

// ... Работаем с буфером здесь ...

Теперь же я хочу сделать то же самое, но с использованием std::string вместо char[]. Я хотел бы избежать использования циклов, то есть я не хочу:

std::ifstream t;
t.open("file.txt");
std::string buffer;
std::string line;
while(t){
    std::getline(t, line);
    // ... добавляем строку к буферу и продолжаем
}
t.close();

Есть идеи, как это можно реализовать?

5 ответ(ов)

11

Есть несколько вариантов. Один из тех, что мне нравится, использует stringstream в качестве промежуточного звена:

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

Официально это не обязано работать в соответствии со стандартом C98 или C03 (строка не обязана хранить данные последовательно), но на практике это работает во всех известных реализациях, а начиная с C++11 это требование также включается, так что с ними это гарантированно будет работать.

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

0

Лучший способ — использовать строковый поток. Это просто и быстро!!!

#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream
int main() {
    std::ifstream inFile;
    inFile.open("inFileName"); // открываем входной файл

    std::stringstream strStream;
    strStream << inFile.rdbuf(); // читаем файл
    std::string str = strStream.str(); // str содержит содержимое файла

    std::cout << str << "\n"; // теперь вы можете делать что угодно со строкой!!!
}

Если у вас есть вопросы или нужно что-то уточнить, не стесняйтесь спрашивать!

0

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

#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');

Этот код считывает содержимое файла filename.txt в строку file_content целиком. Метод std::getline с третьим параметром, равным '\0', позволяет считывать файл до конца, что удобно, если нужно загрузить все данные сразу. Обратите внимание, что данный метод требует, чтобы файл был открыт правильно, а в случае ошибки его стоит проверить перед чтением.

0

Вы можете использовать один из следующих двух методов для чтения содержимого файла в строку:

Первый метод:

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"); // открываем файл

    stringstream strStream;
    strStream << inFile.rdbuf(); // читаем содержимое файла
    return strStream.str(); // strStream содержит содержимое файла
}

Этот метод сначала открывает файл, затем считывает его содержимое в поток stringstream, а затем возвращает его в виде строки.

Выберите метод, который вам больше подходит в зависимости от ваших потребностей при работе с файлами.

0

Вы можете использовать другой способ, который работает с большинством потоков ввода (istream), включая std::cin. Вот пример функции, которая читает данные из файла и возвращает их в виде строки:

std::string readFile()
{
    std::stringstream str;
    std::ifstream stream("Hello_World.txt");
    if (stream.is_open())
    {
        while (stream.peek() != EOF)
        {
            str << (char) stream.get();
        }
        stream.close();
        return str.str();
    }
    return ""; // Возврат пустой строки, если файл не открыт
}

В этом коде мы используем std::ifstream для открытия файла "Hello_World.txt". Если файл успешно открыт, мы считываем его содержимое в строковый поток stringstream. Цикл продолжается до тех пор, пока в потоке есть данные, проверяемые с помощью peek(). Это гарантирует, что мы не читаем за пределами файла. После завершения чтения поток закрывается, и содержимое возвращается в виде строки.

Также стоит учитывать, что если файл по какой-то причине не удастся открыть, функция просто вернет пустую строку. Вы можете улучшить обработку ошибок в зависимости от ваших потребностей.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь