Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

Чтение в 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>());

В вектор <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());

file.txt - всего лишь пример, все отлично работает и для двоичных файлов, просто убедитесь, что вы используете ios:: binary в конструкторе ifstream.

Ответ 2

Там другой поток по этому вопросу.

Мои решения из этой нити (как однострочные):

Хорошее (см. Миланское второе решение):

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

и быстрый:

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

Ответ 3

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

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

Все лучшее

/Роберт

Ответ 4

Но будьте осторожны, что строка С++ - или более конкретная: STL-строка - это всего лишь C-String, способная удерживать строку длины арбитража - разумеется, не!

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

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

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

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

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

Ответ 5

Мне нравится Милан char *, но с 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:: в зависимости от того, хотите ли вы преобразовать строки или нет. Вы также можете изменить 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";
}