В C++ Читайте на iStream в строку с исключениями


Я покрыть все основания? Это может быть улучшено (лучшие практики)?

Редактировать... я пришел с некоторыми улучшениями. Когда я пытался изменить код, программное обеспечение жаловался слишком много кода и слишком мало вякать (перефразирование). Итак, я здесь наговорил. Когда у меня достаточно разболталась, приведенный ниже код будет новый материал.

//#include <libdj/istream.h>

#include <istream>
#include <string>
#include <stdexcept>

namespace dj {
    inline
    void append_istream_onto_string(std::istream& inp, std::string &outp) {
        // Uses inp.seekg(), and inp.tellg() to determine size
        // Throws (std::) invalid_argument, runtime_error, bad_alloc, length_error
        if (!inp.good()) {
            throw std::invalid_argument
              ("Input stream is not valid. (read_istream_into_string)");
        }
        if (!inp.seekg(0, std::ios::end)) {
            throw std::runtime_error
            ("Cannot deduce length of input stream. (read_istream_into_string)");
        }
        outp.reserve(outp.size() + inp.tellg()); // Throws bad_alloc and length_error
        if (!inp.seekg(0, std::ios::beg)) {
            throw std::runtime_error
              ("Input stream seek failed. (read_istream_into_string)");
        }
        outp.append((std::istreambuf_iterator<char>(inp)),
            std::istreambuf_iterator<char>());
    }

    inline
    std::string to_string(std::istream& inp) {
        std::string ret;
        append_istream_onto_string(inp, ret);
        return ret;
    }
}
#include <fstream>

int main() {

    std::ifstream inp("junk.txt");

    std::string buffer;
    buffer = "// junk.txt\n";
    try {
        //dj::append_istream_onto_string(inp, buffer);
        buffer = dj::to_string(inp);
    } catch (const std::exception &ex) {
        std::cout << ex.what() << std::endl;
    }
    std::cout << buffer << std::endl;
}


838
5
задан 24 февраля 2018 в 12:02 Источник Поделиться
Комментарии
1 ответ

Потоки-это ужасно. Не использовать их. (Шучу, но я бы хотел иметь жизнеспособную альтернативу рекомендую для основного входного файла. C++ является жалким в этой области.)


  • [кода:] tellg() возвращает знаковый тип, С -1 как значение ошибки. Вы могли бы проверить это, а потом static_cast перед использованием ее в reserve().

  • [кода:] через std::string::resize() и std::istream::read() для копирования из потока может быть быстрее, чем через std::string::append() С std::istreambuf_iteratorС.

  • [дизайн(баг?):] Ищу до конца файла, как это может не сработать. В Windows, например, если файл открыт в текстовом режиме, нажатие Ctrl-Z (в alt026) характер рассматривается как конец файла (хотя это не так). Как я понимаю, вы должны использовать ignore() чтобы найти настоящий конец файла вместо.

  • [дизайн:] я сомневаюсь, что это стоит, чтобы создать функцию, чтобы добавить строку напрямую. Погрузка в строку, то дописывание является, вероятно, достаточно быстро. (Что, если вы хотите, чтобы добавить или вставить... вдруг вам нужно больше функций, которые в принципе делают то же самое).

  • Писать юнит-тесты! Что-то вроде этого нужна целая куча тестов, которые сохранить строку в файл, а затем загрузить строку и сравниваем результаты (в двоичном режиме, режиме текста, специальных символов и т. д.).

В целом статья по ссылке выше - это полезно, но резюме в конце описывает 3 разумных альтернатив для чтения из файлового потока:


  • Поставить istreamrdbuf в stringstream, а затем использовать .str() функцию, чтобы получить строку. Это предполагает дополнительную копирование, но простой, и должен быть достаточно быстрым.

  • Использовать .ignore() чтобы найти конец файла, то прочтите целиком. Никаких дополнительных копий в памяти (хорошо для больших файлов), но включает в себя чтение файл дважды.

  • Читал кусками в std::deque а потом скопировать. Работ, где невозможно искать в потоке.

1
ответ дан 3 марта 2018 в 12:03 Источник Поделиться