Поделиться через


Буферизация файлов

В этом разделе рассматриваются различные рекомендации по управлению буферизацией файлов, которые также называются небуферированными входными и выходными данными файлов (ввода-вывода). Буферизация файлов обычно обрабатывается системой за кулисами и считается частью кэширования файлов в операционной системе Windows, если иное не указано. Хотя термины кэширования и буферизации иногда используются взаимозаменяемо, в этой теме термин буферизация используется специально в контексте объяснения, как взаимодействовать с данными, которые не кэшируются и не буферизуются системой, где в противном случае они в значительной степени не подлежат прямому управлению приложениями в пользовательском режиме.

При открытии или создании файла с функцией CreateFileможно указать флагFILE_FLAG_NO_BUFFERING, чтобы отключить системное кэширование данных, считываемых из или записанных в файл. Хотя это обеспечивает полный и прямой контроль над буферизацией данных, в случае файлов и аналогичных устройств существуют требования к выравниванию данных, которые необходимо учитывать.

Заметка

Эта информация о выравнивании применяется к устройствам ввода-вывода, таким как файлы, поддерживающие поиск и концепцию указателей положения файла (или смещения). Для устройств, которые не предусматривают поиска, например, именованные каналы или устройства связи, отключение буферизации может не требовать какого-либо выравнивания. Любые ограничения или эффективность, которые могут быть получены путем выравнивания в этом случае, зависят от базовой технологии.

 

В простом примере приложение откроет файл для записи с флагом FILE_FLAG_NO_BUFFERING, а затем выполнит вызов функции WriteFile с помощью буфера данных, определенного в приложении. Этот локальный буфер в этих обстоятельствах фактически является единственным буфером файлов, который существует для этой операции. Из-за макета физического диска, макета хранилища файловой системы и отслеживания положения указателя файлов на уровне системы эта операция записи может завершиться ошибкой, если определенные локально буферы данных не соответствуют определённым критериям выравнивания, которые описаны в следующем разделе.

Заметка

Обсуждение кэширования не учитывает аппаратное кэширование на самом физическом диске, которое в любом случае может не находиться под прямым контролем системы. Это не влияет на требования, указанные в этом разделе.

 

Дополнительные сведения о том, как FILE_FLAG_NO_BUFFERING взаимодействует с другими флагами, связанными с кэшем, см. в разделе CreateFile.

Требования к выравниванию и доступу к файлам

Как уже говорилось ранее, приложение должно соответствовать определенным требованиям при работе с файлами, открытыми с FILE_FLAG_NO_BUFFERING. Применяются следующие особенности:

  • Размеры доступа к файлу, включая необязательное смещение файла в структуре OVERLAPPED, если оно указано, должны быть кратны размеру сектора тома. Например, если размер сектора составляет 512 байт, приложение может запрашивать операции чтения и записи 512, 1 024, 1536 или 2 048 байт, но не 335, 981 или 7 171 байт.
  • Адреса буферов для доступа к файлам при операциях чтения и записи должны быть синхронизированы с физическими секторами, то есть выровнены по адресам в памяти, которые являются целыми числами размера физического сектора тома. В зависимости от диска это требование может не применяться.

Разработчики приложений должны учитывать новые типы устройств хранения, введенных на рынок с размером физического сектора мультимедиа размером 4096 байт. Отраслевое название для этих устройств — "Расширенный формат". Так как могут возникнуть проблемы с совместимостью напрямую при вводе 4 096 байтов в качестве единицы адресации для носителя, временное решение совместимости заключается в создании устройств, которые эмулируют обычное 512-байтовое устройство хранилища сектора, но предоставляют доступную информацию о истинном размере сектора с помощью стандартных команд ATA и SCSI.

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

  • Логический сектор: единица, используемая для адресации логических блоков на носителе данных. Мы также можем подумать об этом как о наименьшей единице записи, которую может принять хранилище. Это "эмуляция".
  • Физический сектор: единица, для которой операции чтения и записи на устройство выполняются в одной операции. Это единица атомарной записи, и то, к чему операции ввода-вывода без буфера должны быть выровнены, чтобы иметь оптимальные характеристики производительности и надежности.

Большинство текущих API Windows, таких как IOCTL_DISK_GET_DRIVE_GEOMETRY и GetDiskFreeSpace, возвращает размер логического сектора, но размер физического сектора можно получить с помощью кода элемента управления IOCTL_STORAGE_QUERY_PROPERTY с соответствующими сведениями, содержащимися в элементе BytesPerPhysicalSector в структуре STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR. Пример см. в образце кода STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR. Корпорация Майкрософт настоятельно рекомендует разработчикам выравнивать небуферированные операции ввода-вывода по размеру физического сектора, как сообщается в коде управления IOCTL_STORAGE_QUERY_PROPERTY, чтобы обеспечить подготовку приложений к переходу по размеру сектора.

Windows Server 2003 и Windows XP: структура STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR недоступна. Она появилась в Windows Vista и Windows Server 2008.

Так как адреса буферов для операций чтения и записи должны быть выровнены по секторам, приложение должно иметь прямой контроль над выделением этих буферов. Один способ выравнивания буферов — использовать функцию VirtualAlloc для выделения буферов. Рассмотрим следующее:

  • VirtualAlloc выделяет память, выравниваемую по адресам, являющимся целыми кратными размеру страницы системы. Размер страницы составляет 4096 байт для систем на основе Itanium на x64 и x86 или 8 192 байтах. Дополнительные сведения см. функцию GetSystemInfo.
  • Размер сектора обычно составляет от 512 до 4096 байт для устройств хранения прямого доступа (жестких дисков) и 2 048 байт для CD-ROM.
  • Размеры страницы и сектора являются степенями двойки.

Поэтому в большинстве случаев память, выровненная по страницам, также будет выровнена по секторам, поскольку случай, когда размер сектора превышает размер страницы, встречается редко.

Другим способом получения буферов памяти, выровненных вручную, является использование функции _aligned_malloc из библиотеки Run-Time C. Пример выравнивания буфера вручную см. в примере кода языка C++ в разделе "Пример кода" WriteFile.