Каков самый элегантный способ чтения текстового файла с помощью c++?


Я хотел бы прочитать все содержимое текстового файла в std::string объект с c++.

С Python, я могу написать:

text = open("text.txt", "rt").read()

это очень просто и элегантно. Я ненавижу уродливые вещи, поэтому я хотел бы знать - каков самый элегантный способ чтения текстового файла с помощью C++? Спасибо.

5 55

5 ответов:

есть много способов, вы выбираете наиболее элегантный для вас.

чтение в char*:

ifstream file ("file.txt", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
    file.seekg(0, ios::end);
    size = file.tellg();
    char *contents = new char [size];
    file.seekg (0, ios::beg);
    file.read (contents, size);
    file.close();
    //... do something with it
    delete [] contents;
}

в std:: string:

std::ifstream in("file.txt");
std::string contents((std::istreambuf_iterator<char>(in)), 
    std::istreambuf_iterator<char>());

в вектор:

std::ifstream in("file.txt");
std::vector<char> contents((std::istreambuf_iterator<char>(in)),
    std::istreambuf_iterator<char>());

в строку, используя stringstream:

std::ifstream in("file.txt");
std::stringstream buffer;
buffer << in.rdbuf();
std::string contents(buffer.str());
.txt-это просто пример, все отлично работает и для двоичных файлов, просто убедитесь, что вы используете ios::binary в конструкторе ifstream.

здесь еще один поток на эту тему.

мои решения из этой темы (как вкладыши):

Ницца (см. Второе решение Милана):

string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());

и быстро:

string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str());

вы, кажется, говорите об элегантности как об определенном свойстве "маленького кода". Это, конечно, субъективно в какой-то степени. Некоторые скажут, что опустить всю обработку ошибок не очень элегантно. Некоторые скажут, что четкий и компактный код, который вы сразу понимаете, элегантен.

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

все лучший

/Роберт

но будьте осторожны, что c++-строка (или более конкретно: STL-строка) так же мало, как C-строка, способная удерживать строку произвольной длины - конечно, нет!

взгляните на элемент max_size (), который дает вам максимальное количество символов, которое может содержать строка. Это определенный номер реализации и не может быть переносимым между различными платформами. Visual Studio дает значение около 4gigs для строк, другие могут дать вам только 64k и на 64Bit-платформах это может дать вам что-то действительно огромное! Это зависит и, конечно, обычно вы столкнетесь с bad_alloc-исключением из-за исчерпания памяти долгое время до достижения предела 4gig...

BTW: max_size () также является членом других STL-контейнеров! Это даст вам максимальное количество элементов определенного типа (для которых вы создали экземпляр контейнера), которые этот контейнер (теоретически) сможет содержать.

Итак, если Вы читаете из файла неизвестного происхождения вы должны:
- Проверьте его размер и убедитесь, что он меньше, чем max_size()
- Поймать и обработать bad_alloc-исключения

и еще один момент: Почему вы заинтересованы в чтении файла в строку? Я бы ожидал дальнейшей обработки, постепенно разбирая его или что-то еще, верно? Поэтому вместо того, чтобы читать его в строку, вы можете также прочитать его в stringstream (который в основном является просто некоторым синтаксическим сахаром для строки) и выполнить обработку. Но тогда вы могли бы сделать обработки непосредственно из файла, а также. Потому что при правильном программировании stringstream может быть легко заменен filestream, т. е. самим файлом. Или любым другим входным потоком, все они имеют одинаковые члены и операторы и, таким образом, могут быть легко заменены!

и для самой обработки: есть также много, что вы можете автоматизировать компилятором! Например, допустим, вы хотите маркировать строку. При определении правильного шаблона выполните следующие действия действия:
- Чтение из файла (или строки или любого другого входного потока)
- Токенизация контента
- pushing все найденные маркеры в STL-контейнер
- сортировка маркеров в алфавитном порядке
- выделение любых двойных значений
может все(!!) быть достигнутым в одном единственном(!) строка C++ - кода (оставим в стороне сам шаблон и обработку ошибок)! Это всего лишь один вызов функции std:: copy()! Просто google для "token iterator", и вы получите представление о том, что я имею в виду. Так это кажется мне еще более "элегантным", чем просто чтение из файла...

мне нравится миланский char * way, но с std::string.


#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;

string& getfile(const string& filename, string& buffer) {
    ifstream in(filename.c_str(), ios_base::binary | ios_base::ate);
    in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit);
    buffer.resize(in.tellg());
    in.seekg(0, ios_base::beg);
    in.read(&buffer[0], buffer.size());
    return buffer;
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        cerr << "Usage: this_executable file_to_read\n";
        return EXIT_FAILURE;
    }
    string buffer;
    cout << getfile(argv[1], buffer).size() << "\n";
}

(С или без ios_base::binary, в зависимости от того, хотите ли вы переводить новые строки или нет. Вы также можете изменить getfile, чтобы просто вернуть строку, чтобы вам не нужно было передавать строку буфера. Затем проверьте, оптимизирует ли компилятор копию при возврате.)

однако, это может выглядеть немного лучше (и намного медленнее):


#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;

string getfile(const string& filename) {
    ifstream in(filename.c_str(), ios_base::binary);
    in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit);
    return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>());
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        cerr << "Usage: this_executable file_to_read\n";
        return EXIT_FAILURE;
    }
    cout << getfile(argv[1]).size() << "\n";
}