Запишите все, кроме первых N строк потока, не разрушая целевой поток

0

Как вы можете писать все, кроме первых N строк потока, не повреждая поток назначения?

Например, следующее работает отлично, когда источник имеет n-1 или меньше строк и когда источник имеет n + 1 или более строк, но иногда терпит неудачу, когда источник имеет ровно n строк:

void copy_all_but_first_n_lines(std::ifstream& source, std::ofstream& dest, size_t n)
{
    for (size_t i=0; i<n; ++i)
    {
        std::string line;
        std::getline(source, line);
    }

    if (source.good()) dest << source.rdbuf();

    if (!dest.good()) throw std::runtime_error("destination turned bad after writing remainder of source");
}

С источником с ровно n линиями, пункт назначения иногда имеет набор сбоев.

Этот failbit устанавливается только тогда, когда источник имеет завершающую новую строку. Я тестирую это в Windows, и в шестнадцатеричном редакторе я вижу, что файлы с завершающей новой строкой и ровно n строк приводят к тому, что целевой поток имеет набор сбоев, но файлы с ровно n строками без завершающего конца строки не приводят к в наборе битбит. Все файлы, которые я тестирую, имеют символы новой строки как "\ r\n".

Я попытался открыть потоки в текстовом и двоичном режимах, но это не изменило поведение.


Если я изменю код, чтобы использовать std::copy вместо записи rdbuf, он работает независимо от того, существует ли завершающая rdbuf. В соответствии с этим, эти два должны быть эквивалентными - почему пишет rdbuf сбой, а std :: copy преуспевает?

void copy_all_but_first_n_lines(std::ifstream& source, std::ofstream& dest, size_t n)
{
    for (size_t i=0; i<n; ++i)
    {
        std::string line;
        std::getline(source, line);
    }

    if (source.good())
    {
        std::istreambuf_iterator<char> begin(source);
        std::istreambuf_iterator<char> end;
        std::ostreambuf_iterator<char> destination(dest);
        std::copy(begin, end, destination);
    }

    if (!dest.good()) throw std::runtime_error("destination turned bad after writing remainder of source");
}
Теги:
newline

1 ответ

2
Лучший ответ

Взгляните на стандарт:

basic_ostream<charT,traits>& operator<<(basic_streambuf<charT,traits>* sb);

7 Эффекты: ведет себя как неформатированная выходная функция (как описано в пункте 27.7.3.7, пункт 1). После того, как объект- setstate(badbit) будет построен, если sb является нулевым setstate(badbit) (который может ios_base::failure).
8 Получает символы из sb и вставляет их в *this. Символы считываются из sb и вставляются до тех пор, пока не произойдет следующее:

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

9 Если функция не вставляет никаких символов, она вызывает setstate(failbit) (которая может ios_base::failure (27.5.5.4)). Если при извлечении символа было failbit исключение, функция устанавливает failbit в состояние ошибки, и если failbit в exceptions() исключение пойманное исключается.

Таким образом, они эквивалентны, если будет скопирован хотя бы один символ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню