Как использовать istream со строками
Я хотел бы прочитать файл в строку. Я ищу различные способы, как сделать это эффективно.
использование фиксированного размера * char buffer
Я получил ответ от Тони, что создает буфер 16 КБ и считывает в этот буфер и добавляет буфер, пока больше нечего читать. Я понимаю, как это работает, и я нашел его очень быстро. Что я не понимаю, так это то, что в комментариях этого ответа говорится, что таким образом, все копируется дважды. Но, как я понимаю, это происходит только в памяти, а не с диска, поэтому это почти незаметно. Проблема в том, что он копирует из буфера в строку в памяти?
использования istreambuf_iterator
на другого ответа я получил использования istreambuf_iterator. Код выглядит красиво и минимально, но он очень медленный. Я не знаю, почему это происходит. Почему эти итераторы так медленно?
использование функции memcpy()
на этот вопрос я получил комментарии, что я должен использовать memcpy (), поскольку это самый быстрый собственный метод. Но как я могу использовать memcpy() со строкой и объект ifstream? Не ifstream должен работать со своей функцией чтения? Почему использование memcpy () портит переносимость? Я ищу решение, которое совместимо с VS2010, а также GCC. Почему memcpy () не работает с ними?
+ Любой другой эффективный способ?
Что вы рекомендуете, какую оболочку я использую, для небольших двоичных файлов
(я не хотел разбивать этот вопрос на части, так как меня больше интересует сравнение между разными способами, как я могу прочитать ifstream в строку)
2 ответов
это происходит только в памяти, а не с диска, поэтому почти unnoticable
это действительно так. Тем не менее, решение, которое этого не делает, может быть быстрее.
Почему эти итераторы так медленно?
код медленный не из-за итераторов, а потому, что строка не знает, сколько памяти выделить:istreambuf_iterator
s может быть пройден только один раз, поэтому строка по существу вынуждена выполнять повторение конкатенации с результирующими перераспределениями памяти, которые очень медленные.
мой любимый однострочный, от еще один ответ течет непосредственно из базового буфера:
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
и предварительно выделенный буфер (допустим вы можете найти
соответствующий размер буфера).