ファイルを作成して開く
CreateFile 関数は、新しいファイルを作成したり、既存のファイルを開いたりすることができます。 ファイル名、作成手順、およびその他の属性を指定する必要があります。 アプリケーションが新しいファイルを作成すると、オペレーティング システムによって指定されたディレクトリに追加されます。
オペレーティング システムは、CreateFile を使用して開いたり作成したりする各ファイルに、handle と呼ばれる一意の識別子を割り当てます。 アプリケーションは、ファイルの読み取り、書き込み、記述を行う関数でこのハンドルを使用できます。 これは、そのハンドルへのすべての参照が閉じられるまで有効です。 アプリケーションが起動すると、ハンドルが継承可能として作成されている場合、アプリケーションはそれを起動したプロセスから開いているすべてのハンドルを継承します。
アプリケーションは、CreateFile によって返されるハンドルの値を確認してから、ハンドルを使用してファイルにアクセスする必要があります。 エラーが発生した場合、ハンドル値は INVALID_HANDLE_VALUE となり、アプリケーションは拡張エラー情報に GetLastError 関数を使用できます。
アプリケーションで CreateFile を使用する場合は、 dwDesiredAccess パラメーターを使用して、ファイルからの読み取り、ファイルへの書き込み、読み取りと書き込みの両方を行うかどうかを指定する必要があります。 これは、アクセス モードの要求と呼ばれます。 また、dwCreationDisposition パラメーターを使用して、ファイルが既に存在する場合に実行するアクション (creation disposition と呼ばれます) を指定する必要があります。 たとえば、アプリケーションは dwCreationDisposition を CREATE_ALWAYS に設定して CreateFile を呼び出し、同じ名前のファイルが既に存在する場合でも常に新しいファイルを作成できます (したがって、既存のファイルが上書きされます)。 これが成功するかどうかは、前のファイルの属性やセキュリティ設定などの要因によって異なります (詳細については、次のセクションを参照してください)。
アプリケーションでは、CreateFile を使用して、ファイルの読み取り、書き込み、両方、またはどちらも共有するかどうかを指定します。 これは、共有モードと呼ばれます。 共有されていない開いているファイル (dwShareMode を 0 に設定) は、そのハンドルが閉じられるまで、そのファイルを開いたアプリケーションまたは別のアプリケーションによって再度開くことはできません。 これは排他的アクセスとも呼ばれます。
プロセスで CreateFile を使用して、既に共有モードになっている (dwShareMode が有効な 0 以外の値に設定されている) ファイルを開こうとすると、システムは要求されたアクセスモードと共有モードを、ファイルが開かれたときに指定されたものと比較します。 前の呼び出しで指定したモードと競合するアクセス モードまたは共有モードを指定した場合、CreateFile は失敗します。
次の表は、さまざまなアクセス モードと共有モード (それぞれ dwDesiredAccess、dwShareMode) を使用した CreateFile への 2 つの呼び出しの有効な組み合わせを示しています。 CreateFile 呼び出しがどの順序で行われるかは関係ありません。 ただし、各ファイル ハンドルに対する後続のファイル I/O 操作は、その特定のファイル ハンドルに関連付けられている現在のアクセス モードと共有モードによって制約されます。
CreateFile の最初の呼び出し。 | CreateFile の有効な 2 回目の呼び出し。 |
---|---|
GENERIC_READ、 FILE_SHARE_READ |
|
GENERIC_READ、 FILE_SHARE_WRITE |
|
GENERIC_READ、FILE_SHARE_READ, FILE_SHARE_WRITE |
|
GENERIC_WRITE、FILE_SHARE_READ |
|
GENERIC_WRITE、 FILE_SHARE_WRITE |
|
GENERIC_WRITE、FILE_SHARE_READFILE_SHARE_WRITE |
|
GENERIC_READGENERIC_WRITE、 FILE_SHARE_READ |
|
GENERIC_READ、 GENERIC_WRITE、 FILE_SHARE_WRITE |
|
GENERIC_READGENERIC_WRITE、 FILE_SHARE_READ、 FILE_SHARE_WRITE |
|
標準ファイル属性に加えて、SECURITY_ATTRIBUTES 構造体へのポインターを CreateFile の 4 番目のパラメーターとして含めることで、セキュリティ属性を指定することもできます。 ただし、これが効果を発揮するには、基盤となるファイル システムがセキュリティをサポートしている必要があります (たとえば、NTFS ファイル システムはセキュリティをサポートしていますが、さまざまな FAT ファイル システムはサポートしていません)。 セキュリティ属性の詳細については、「Access Control」を参照してください。
新しいファイルを作成するアプリケーションは、テンプレート ファイルに省略可能なハンドルを提供できます。CreateFile は、このハンドルから新しいファイルを作成するためのファイル属性と拡張属性を受け取ります。
CreateFile のシナリオ
CreateFile 関数を使用してファイルへのアクセスを開始するには、いくつかの基本的なシナリオがあります。 これらの概要を次に示します。
- その名前のファイルがまだ存在しない場合に新しいファイルを作成します。
- 同じ名前のファイルが既に存在する場合でも新しいファイルを作成し、そのデータをクリアして空から開始します。
- 既存のファイルが存在する場合にのみ開き、そのまま開きます。
- 既存のファイルが存在する場合にのみ開き、空に切り捨てます。
- ファイルを常に開く: 存在する場合はそのまま、存在しない場合は新しいファイルを作成します。
これらのシナリオは、dwCreationDisposition パラメーターを適切に使用することによって制御されます。 次は、これらのシナリオがこのパラメーターの値にどのようにマップされるか、および使用された場合の動作の内訳を示しています。
その名前のファイルがまだ存在しない場合 (dwCreationDisposition が CREATE_NEW、 CREATE_ALWAYS、または OPEN_ALWAYS のいずれかに設定されている場合) に新しいファイルを作成または開く場合、CreateFile 関数は次のアクションを実行します。
- dwFlagsAndAttributes で指定されたファイル属性とフラグを FILE_ATTRIBUTE_ARCHIVE と結合します。
- ファイルの長さを 0 に設定します。
- hTemplateFile パラメーターが指定されている場合は、テンプレート ファイルによって指定された拡張属性を新しいファイルにコピーします (これにより、前に指定したすべての FILE_ATTRIBUTE_* フラグがオーバーライドされます)。
- bInheritHandle メンバーで指定された継承フラグと、lpSecurityAttributes パラメーター (SECURITY_ATTRIBUTES 構造体) の lpSecurityDescriptor メンバーで指定されたセキュリティ記述子を設定します (指定されている場合)。
同じ名前のファイルが既に存在する場合でも新しいファイルを作成する場合 (dwCreationDisposition を CREATE_ALWAYS に設定)、CreateFile 関数は次の操作を実行します。
- 現在のファイル属性とセキュリティ設定の書き込みアクセスを確認します。拒否された場合は失敗します。
- dwFlagsAndAttributes で指定されたファイル属性とフラグを FILE_ATTRIBUTE_ARCHIVE と既存のファイル属性と組み合わせます。
- ファイルの長さをゼロに設定します (つまり、ファイル内にあったデータは使用できなくなり、ファイルは空になります)。
- hTemplateFile パラメーターが指定されている場合は、テンプレート ファイルによって指定された拡張属性を新しいファイルにコピーします (これにより、前に指定したすべての FILE_ATTRIBUTE_* フラグがオーバーライドされます)。
- lpSecurityAttributes パラメーター (SECURITY_ATTRIBUTES 構造体) の bInheritHandle メンバーによって指定された継承フラグを設定しますが、SECURITY_ATTRIBUTES 構造体の lpSecurityDescriptor メンバーは無視します。
- それ以外の場合 (つまり、CreateFile は有効なハンドルを返します)、GetLastError を呼び出すと、コード ERROR_ALREADY_EXISTS が生成されます。ただし、この特定のユース ケースでは、実際にはエラーになりません (既存のファイルの代わりに "新しい" (空の) ファイルを作成する場合)。
既存のファイル (dwCreationDispositionOPEN_EXISTING、 OPEN_ALWAYS、または TRUNCATE_EXISTING のいずれかに設定されている場合)、CreateFile 関数は次のアクションを実行します。
- 要求されたアクセスの現在のファイル属性とセキュリティ設定をチェックし、拒否された場合は失敗します。
- dwFlagsAndAttributes で指定されたファイル フラグ (FILE_FLAG_*) を既存のファイル属性と結合し、dwFlagsAndAttributes で指定されたファイル属性 (FILE_ATTRIBUTE_*) を無視します。
- dwCreationDisposition が TRUNCATE_EXISTING に設定されている場合にのみ、ファイルの長さを 0 に設定します。それ以外の場合は、現在のファイルの長さが維持され、ファイルがそのまま開かれます。
- hTemplateFile パラメーターを無視します。
- lpSecurityAttributes パラメーター (SECURITY_ATTRIBUTES 構造体) の bInheritHandle メンバーによって指定された継承フラグを設定しますが、SECURITY_ATTRIBUTES 構造体の lpSecurityDescriptor メンバーは無視します。
ファイルの属性とディレクトリ
ファイル属性は、ファイルまたはディレクトリに関連付けられたメタデータの一部であり、それぞれに独自の目的と、設定および変更方法に関するルールがあります。 これらの属性の一部はファイルにのみ適用され、一部はディレクトリにのみ適用されます。 たとえば、FILE_ATTRIBUTE_DIRECTORY 属性はディレクトリにのみ適用されます。これは、ファイル システムによって、ディスク上のオブジェクトがディレクトリであるかどうかを判断するために使用されますが、既存のファイル システム オブジェクトの場合は変更できません。
一部のファイル属性はディレクトリに対して設定できますが、その属性はそのディレクトリ内に作成されたファイルに対してのみ意味を持ち、既定の属性として機能します。 たとえば、FILE_ATTRIBUTE_COMPRESSED ディレクトリ オブジェクトに設定できますが、ディレクトリ オブジェクト自体に実際のデータが含まれていないため、実際には圧縮されません。ただし、この属性でマークされたディレクトリは、そのディレクトリに追加された新しいファイルを圧縮するようにファイル システムに指示します。 ディレクトリに設定でき、そのディレクトリに追加された新しいファイルにも設定されるファイル属性は、inherited 属性と呼ばれます。
CreateFile 関数は、ファイルの作成時に特定のファイル属性を設定するためのパラメーターを提供します。 一般に、これらの属性は、アプリケーションがファイル作成時に使用するのが最も一般的ですが、CreateFile で使用できるすべてのファイル属性はありません。 一部のファイル属性では、ファイルが既に存在ている後で、SetFileAttributes、 DeviceIoControl、 DecryptFile などの他の関数を使用する必要があります。 FILE_ATTRIBUTE_DIRECTORY の場合、CreateFile ではディレクトリを作成できないため、作成時に CreateDirectory 関数が必要です。 特別な処理を必要とするその他のファイル属性は FILE_ATTRIBUTE_REPARSE_POINT と FILE_ATTRIBUTE_SPARSE_FILE であり、DeviceIoControl が必要です。 詳細については、「SetFileAttributes」を参照してください。
前述のように、ファイル属性の継承は、ファイルが配置されるディレクトリ属性からファイル属性を読み取ってファイルが作成されるときに発生します。 次の表は、これらの継承された属性と、CreateFile 機能との関係をまとめたものです。
ディレクトリ属性の状態 | CreateFile 新しいファイルの継承オーバーライド機能 |
---|---|
FILE_ATTRIBUTE_COMPRESSED 設定します。 |
コントロールはありません。 DeviceIoControl を使用してクリアします。 |
FILE_ATTRIBUTE_COMPRESSED 設定しません。 |
コントロールはありません。 DeviceIoControl を使用して設定します。 |
FILE_ATTRIBUTE_ENCRYPTED 設定します。 |
コントロールはありません。 DecryptFile を使用します。 |
FILE_ATTRIBUTE_ENCRYPTED 設定しません。 |
CreateFile を使用して設定できます。 |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 設定します。 |
コントロールはありません。 SetFileAttributes を使用してクリアします。 |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 設定しません。 |
コントロールはありません。 SetFileAttributes を使用して設定します。 |