Как использовать istream со строками

Я хотел бы прочитать файл в строку. Я ищу различные способы, как сделать это эффективно.

использование фиксированного размера * char buffer

Я получил ответ от Тони, что создает буфер 16 КБ и считывает в этот буфер и добавляет буфер, пока больше нечего читать. Я понимаю, как это работает, и я нашел его очень быстро. Что я не понимаю, так это то, что в комментариях этого ответа говорится, что таким образом, все копируется дважды. Но, как я понимаю, это происходит только в памяти, а не с диска, поэтому это почти незаметно. Проблема в том, что он копирует из буфера в строку в памяти?

использования istreambuf_iterator

на другого ответа я получил использования istreambuf_iterator. Код выглядит красиво и минимально, но он очень медленный. Я не знаю, почему это происходит. Почему эти итераторы так медленно?

использование функции memcpy()

на этот вопрос я получил комментарии, что я должен использовать memcpy (), поскольку это самый быстрый собственный метод. Но как я могу использовать memcpy() со строкой и объект ifstream? Не ifstream должен работать со своей функцией чтения? Почему использование memcpy () портит переносимость? Я ищу решение, которое совместимо с VS2010, а также GCC. Почему memcpy () не работает с ними?

+ Любой другой эффективный способ?

Что вы рекомендуете, какую оболочку я использую, для небольших двоичных файлов

(я не хотел разбивать этот вопрос на части, так как меня больше интересует сравнение между разными способами, как я могу прочитать ifstream в строку)

2 ответов


это происходит только в памяти, а не с диска, поэтому почти unnoticable

это действительно так. Тем не менее, решение, которое этого не делает, может быть быстрее.

Почему эти итераторы так медленно?

код медленный не из-за итераторов, а потому, что строка не знает, сколько памяти выделить:istreambuf_iterators может быть пройден только один раз, поэтому строка по существу вынуждена выполнять повторение конкатенации с результирующими перераспределениями памяти, которые очень медленные.

мой любимый однострочный, от еще один ответ течет непосредственно из базового буфера:

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

на последних платформах это действительно предварительно выделит буфер. Однако это все равно приведет к избыточной копии (из stringstream в последней строке).


наиболее общим способом, вероятно, будет ответ с использованием istreambuf_iterator:

std::string s( (std::istreambuf_iterator<char>( source )),
               (std::istreambuf_iterator<char>()) );

Хотя точная производительность очень зависит от реализации, это маловероятно, что это самое быстрое решение.

интересной альтернативой было бы:

std::istringstream tmp;
tmp << source.rdbuf();
std::string s( tmp.str() );

это может быть очень быстрым, если реализация имеет хорошую работу на the operator<< вы используете, и в том, как он растет строка внутри istringstream. Некоторые более ранние реализации (и, возможно, sone больше недавние тоже) были очень плохими в этом, однако.

в общем, производительность, используя std::string будет зависеть от того, насколько эффективная реализация заключается в росте строки; реализация не могу определить, насколько большой он должен быть изначально. Возможно, вы захотите сравните первый алгоритм, использующий тот же код с std::vector<char> вместо std::string, или если вы можете сделать хорошую оценку максимальный размер, используя reserve, или что-то например:

std::string s( expectedSize, '' );
std::copy( std::istreambuf_iterator<char>( source ),
           std::istreambuf_iterator<char>(),
           s.begin() );

memcpy не удается прочитать из файла, и с хорошим компилятором, не будет так же быстро, как с помощью std::copy (С теми же типами данных).

я склонен использовать второе решение, выше, с << на rdbuf(), но это частично по историческим причинам, я привык делая это (используя istrstream) прежде чем STL был добавлен к стандарту библиотека. Если на то пошло, вы можете поэкспериментировать с istrstream и предварительно выделенный буфер (допустим вы можете найти соответствующий размер буфера).