Обычный способ чтения файла в C ++ такой:
std::ifstream file("file.txt", std::ios::binary | std::ios::ate);
std::vector<char> data(file.tellg());
file.seekg(0, std::ios::beg);
file.read(data.data(), data.size());
Чтение файла объемом 1,6 МБ происходит практически мгновенно.
Но недавно я обнаружил std:: istream_iterator и хотел попробовать это для того, чтобы написать красивый однострочный способ чтения содержимого файла.Например:
std::vector<char> data(std::istream_iterator<char>(std::ifstream("file.txt", std::ios::binary)), std::istream_iterator<char>());
Код хороший, но очень медленный.Чтобы прочитать тот же файл объемом 1,6 МБ, требуется около 2/3 секунд.Я понимаю, что это может быть не самый лучший способ чтения файла, но почему это так медленно?
Чтение файла классическим способом происходит так (я говорю толькоо функции чтения):
- istream содержит filebuf , который содержит блок данных из файла
- , функция чтения вызывает sgetn из filebuf, который копирует символы один за другим (без memcpy) из внутреннего буфера в буфер «data»
- когда данные внутри filebuf полностью читаются, filebuf читает следующееблок из файла
Когда вы читаете файл с помощью istream_iterator, он выглядит следующим образом:
- вектор вызывает * итератор для получения следующего символа (это просто читаетпеременная), добавляет его в конец и увеличивает его собственный размер
- , если выделенное пространство вектора заполнено (что происходит не так часто), перемещение выполняется
- , тогда он вызывает ++ итераторкоторый читает следующий символ из потока (опеrator >> с параметром char, который, безусловно, просто вызывает функцию sbumpc в filebuf)
- , наконец, он сравнивает итератор с конечным итератором, что делается путем сравнения двух указателей
IДолжен признать, что второй способ не очень эффективен, но, по крайней мере, в 200 раз медленнее, чем первый, как это возможно?
Я думал, что снижение производительности - это перемещение или вставка, но я пыталсясоздание целого вектора и вызов std :: copy, и это так же медленно.
// also very slow:
std::vector<char> data2(1730608);
std::copy(std::istream_iterator<char>(std::ifstream("file.txt", std::ios::binary)), std::istream_iterator<char>(), data2.begin());