ファイルのバッファリング

このトピックでは、バッファーなしファイル入出力 (I/O) とも呼ばれる、ファイル バッファリングのアプリケーション制御に関するさまざまな考慮事項について説明します。 通常、ファイル バッファリングはバックグラウンドでシステムによって処理され、特に指定がない限り、Windows オペレーティング システム内の ファイル キャッシュ の一部と見なされます。 キャッシュバッファリングという用語は同じ意味で使用される場合がありますが、このトピックでは、特に、システムによってキャッシュ (バッファー) されていないデータと対話する方法を説明するコンテキストでバッファーリングという用語を使用します。それ以外の場合は、ユーザー モード アプリケーションの直接制御からほとんど制御されません。

CreateFile 関数を使用してファイルを開いたり作成したりする場合は、FILE_FLAG_NO_BUFFERING フラグを指定して、ファイルからの読み取りまたはファイルへの書き込み中のデータのシステム キャッシュを無効にすることができます。 これにより、データ I/O バッファリングを完全かつ直接的に制御できますが、ファイルや同様のデバイスの場合は、考慮する必要があるデータアラインメント要件があります。

Note

このアラインメント情報は、シークをサポートするファイルやファイル位置ポインター (またはオフセット) の概念などのデバイスの I/O に適用 されます。 名前付きパイプや通信デバイスなど、シークしないデバイスの場合、バッファリングをオフにすると、特定の配置が必要ない場合があります。 その場合にアラインメントによって得られる可能性のある制限事項または効率は、基になるテクノロジに依存します。

 

簡単な例では、アプリケーションは、 FILE_FLAG_NO_BUFFERING フラグを使用して書き込みアクセス用のファイルを開き、アプリケーション内で定義されたデータ バッファーを使用して WriteFile 関数の呼び出しを実行します。 このローカル バッファーは、このような状況では、実質的にこの操作に存在する唯一のファイル バッファーです。 この書き込み操作は、物理ディスク レイアウト、ファイル システム ストレージ レイアウト、およびシステム レベルのファイル ポインター位置追跡のため、ローカルに定義されたデータ バッファーが特定の配置基準を満たさない限り失敗します。これについては、次のセクションで説明します。

Note

キャッシュの説明では、物理ディスク自体のハードウェア キャッシュは考慮されません。これは、いずれの場合もシステムの直接制御内にあるとは限りません。 これは、このトピックで指定されている要件には影響しません。

 

FILE_FLAG_NO_BUFFERINGが他 キャッシュ関連フラグと対話する方法の詳細については、「 CreateFile」を参照してください。

配置とファイル アクセスの要件

前に説明したように、アプリケーションは、FILE_FLAG_NO_BUFFERINGで開かれたファイルを操作するときに、特定の要件 満たす必要があります。 次の詳細が適用されます。

  • 指定した場合、 OVERLAPPED 構造体のオプションのファイル オフセットを含むファイル アクセス サイズは、ボリューム セクター サイズの整数倍数であるバイト数に対してである必要があります。 たとえば、セクター サイズが 512 バイトの場合、アプリケーションは 512、1,024、1,536、または 2,048 バイトの読み取りと書き込みを要求できますが、335、981、または 7,171 バイトは要求できません。
  • 読み取りおよび書き込み操作のファイル アクセス バッファー アドレスは、物理セクターアラインメントにする必要があります。つまり、ボリュームの物理セクター サイズの整数倍数であるメモリ内のアドレスにアラインされます。 ディスクによっては、この要件が適用されない場合があります。

アプリケーション開発者は、4,096 バイトの物理メディア セクター サイズで市場に導入される新しい種類のストレージ デバイスに注意する必要があります。 これらのデバイスの業界名は"Advanced Format"です。 メディアのアドレス指定の単位として 4,096 バイトを直接導入する場合に互換性の問題が発生する可能性があるため、一時的な互換性ソリューションは、通常の 512 バイトのセクター ストレージ デバイスをエミュレートするが、標準の ATA コマンドと SCSI コマンドを使用して真のセクター サイズに関する情報を提供するデバイスを導入することです。

このエミュレーションの結果として、開発者が理解する必要がある 2 つのセクター サイズが本質的に存在します。

  • 論理セクター: メディアの論理ブロック アドレス指定に使用される単位。 また、ストレージで受け入れられる最小の書き込み単位と考えることもできます。 これは "エミュレーション" です。
  • 物理セクター: デバイスに対する読み取り操作と書き込み操作が 1 回の操作で完了するユニット。 これはアトミック書き込みの単位であり、最適なパフォーマンスと信頼性の特性を持つためにバッファーなしの I/O をに合わせる必要があります。

IOCTL_DISK_GET_DRIVE_GEOMETRYGetDiskFreeSpace などの最新の Windows API は論理セクター サイズを返しますが、物理セクター サイズは、STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR構造の BytesPerPhysicalSector メンバーに含まれる関連情報を使用して、IOCTL_STORAGE_QUERY_PROPERTYコントロール コードを使用して取得できます。 例については、「 STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR」のサンプル コードを参照してください。 Microsoft では、開発者がこのセクター サイズの移行に備えてアプリケーションを準備できるように、 IOCTL_STORAGE_QUERY_PROPERTY 制御コードによって報告されるバッファーされていない I/O を物理セクター サイズに合わせることを強くお勧めします。

Windows Server 2003 および Windows XP:STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR構造体は使用できません。 Windows Vista と Windows Server 2008 で導入されました。

読み取りおよび書き込み操作のバッファー アドレスはセクターアラインメントする必要があるため、アプリケーションはこれらのバッファーの割り当て方法を直接制御する必要があります。 バッファーをセクターアラインする方法の 1 つは、 VirtualAlloc 関数を使用してバッファーを割り当てることです。 以下、具体例に沿って説明します。

  • VirtualAlloc は、システムのページ サイズの整数倍数であるアドレスにアラインされたメモリを割り当てます。 ページ サイズは、x64 では 4,096 バイト、Itanium ベースのシステムでは x86 または 8,192 バイトです。 詳細については、 GetSystemInfo 関数を参照してください。
  • セクター サイズは、通常、直接アクセス ストレージ デバイス (ハード ドライブ) の場合は 512 ~ 4,096 バイト、CD-ROM の場合は 2,048 バイトです。
  • ページ サイズとセクター サイズはどちらも 2 の累乗です。

したがって、ほとんどの状況では、セクター サイズがページ サイズよりも大きい場合はまれであるため、ページアラインメモリもセクターアラインメントされます。

手動で配置されたメモリ バッファーを取得するもう 1 つの方法は、C Run-Time ライブラリから _aligned_malloc 関数を使用することです。 バッファーの配置を手動で制御する方法の例については、「 WriteFile」の「コード例」セクションの C++ 言語コード例を参照してください。