Как использовать istream со строками - PullRequest
10 голосов
/ 28 июня 2011

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

Использование фиксированного размера * символьный буфер

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

Использование istreambuf_iterator

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

Использование memcpy ()

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

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

Что вы посоветуете, какую оболочку я использую, для небольших бинарных файлов размером <10 МБ? </p>

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

Ответы [ 2 ]

9 голосов
/ 28 июня 2011

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

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

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

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

Мой любимыйone-liner, из другой ответ потоковая передача напрямую из нижележащего буфера:

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

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

4 голосов
/ 28 июня 2011

Наиболее общим способом, вероятно, будет ответ, использующий 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() );

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

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

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

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

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

...