Если вы читаете байт за раз, то у каждого вызываемого вами байта есть издержки вызова функции для чтения байта и дополнительные издержки (например, выполнение fileposition += 1
для запоминания места в файле, где вы находитесь, проверка достижения файла и т. д.)
Если вы прочитали 4000 байтов, то у вас будут те же издержки (в приведенном выше примере 1 вызов функции, одно добавление (fileposition + = 4000) и одна проверка, чтобы увидеть, находитесь ли вы в конце файла. Что касается накладных расходов, вы только что сделали это в 4000 раз быстрее (на самом деле, есть и другие затраты, поэтому вы не увидите такого большого выигрыша, но вы резко сократили накладные расходы)
Конечно, вы можете создать буфер размером с весь файл и получить абсолютные минимальные накладные расходы. Однако:
файл может быть огромным - больше, чем объем памяти, доступный вашей программе, так что это просто не удастся. Или он может быть настолько большим, что вы начнете использовать виртуальную память, и это резко замедлит процесс. Таким образом, разбивая его на более мелкие фрагменты, вы можете копировать неограниченное количество данных, используя небольшой буфер фиксированного размера
ваша ОС и устройства могут одновременно считывать и записывать данные (например, копировать с одного физического диска на другой). Если вы прочитали все данные перед тем, как записать все данные, то вам придется ждать полного чтения, прежде чем вы сможете начать запись. Но во многих случаях вы можете выполнять обе операции параллельно - так что читайте небольшой фрагмент и начинайте писать «асинхронно» (в фоновом режиме), пока вы возвращаетесь и читаете следующий фрагмент.
Вы получаете убывающую отдачу. Чтение 4 байтов вместо 1 может быть в 4 раза быстрее. Но чтение 4000, 40000 или 400000 не ускорит процесс (в действительности, по вышеуказанным причинам большие буферы могут на самом деле замедлить процесс).
В некоторых случаях физические устройства работают с определенными размерами данных (например, 4096 байтов на сектор, 128 байтов на строку кэша, 1500 байтов на пакет данных или 8 байтов (64 бита) по шине ЦП). Разделение данных на куски, которые соответствуют (или кратны) базовому механизму транспорта / хранения, может помочь аппаратному обеспечению более эффективно обрабатывать данные.
Обычно буферы ввода / вывода размером от 4 до 128 КБ работают лучше всего для большинства ситуаций, и вы можете настроить их для конкретной выполняемой операции, поэтому не существует «идеального» размера, подходящего для всех ситуаций.
Обратите внимание, что в большинстве ситуаций ввода / вывода используется много буферов. например При копировании данных с диска (в упрощенном виде) они считываются с диска в кэш для чтения (буфер) на жестком диске, а затем отправляются через интерфейсный кабель на контроллер дисковода компьютера, который также может буферизовать данные. Затем он может быть перенесен в ОЗУ через буфер ввода-вывода, где он удерживается до тех пор, пока ваша программа не будет готова его получить (возможно, он даже будет извлекать данные, прежде чем вы их попросите, так как ожидает, что вы продолжите чтение из тот же файл, и пытается буферизовать данные, чтобы вам не пришлось ждать его). Затем вы читаете это в свой буфер и пишете это. Затем он отправляется в другой буфер ввода-вывода, отправляется на контроллер накопителя, передается на накопитель и кэшируется в кеше записи. В конечном итоге жесткий диск решит сохранить данные в своем кэше записи, и ваша копия будет завершена - большая часть этого происходит в фоновом режиме, поэтому запись может закончиться только через много секунд после того, как ваша программа решит, что она закончила писать и перешел к другой задаче. (Вот почему вы должны «безопасно извлечь» USB-накопители перед их отключением - операционная система, возможно, еще не записала все данные на устройство, даже спустя много секунд после того, как компьютер сказал, что операция копирования завершена) *