Считать целый ASCII-файл в std::string в C++
Проблема: Чтение целого файла в 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 ответ(ов)
Есть несколько вариантов. Один из тех, что мне нравится, использует 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" в преобразованной строке), так что вы просто зарезервировали немного лишнего пространства, которое никогда не используете. Снова, это не создаёт серьёзных проблем, но всё равно кажется немного странным.
Лучший способ — использовать строковый поток. Это просто и быстро!!!
#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"; // теперь вы можете делать что угодно со строкой!!!
}
Если у вас есть вопросы или нужно что-то уточнить, не стесняйтесь спрашивать!
Вы можете не найти этого в книгах или на сайтах, но я обнаружил, что это работает довольно хорошо:
#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');
Этот код считывает содержимое файла filename.txt
в строку file_content
целиком. Метод std::getline
с третьим параметром, равным '\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
, а затем возвращает его в виде строки.
Выберите метод, который вам больше подходит в зависимости от ваших потребностей при работе с файлами.
Вы можете использовать другой способ, который работает с большинством потоков ввода (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()
. Это гарантирует, что мы не читаем за пределами файла. После завершения чтения поток закрывается, и содержимое возвращается в виде строки.
Также стоит учитывать, что если файл по какой-то причине не удастся открыть, функция просто вернет пустую строку. Вы можете улучшить обработку ошибок в зависимости от ваших потребностей.
Как перебрать слова в строке?
Как преобразовать экземпляр std::string в нижний регистр
Вывод строки в текстовый файл
`std::wstring` против `std::string`: когда использовать и в чем разница?
Чтение файла построчно с использованием ifstream в C++