レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API ファイルの概要

Microsoft(R) Windows(TM) では、 ファイルはディスクやテープなどの記憶メディアに格納され、 「ディレクトリ」と呼ばれるグループで組織化されています。Windowsのファイル入出力関数によって、 ファイルやディレクトリの作成、 オープン、 修正、 削除を行うことができます。また、 存在するディスク ドライブなどのシステム情報を取得できます。

次に示すトピックでは、 Windowsのファイルについて説明しています。

システムの構成

ファイルの作成とオープン

ファイルのクローズと削除

ファイルのコピーと移動

ファイルの読み書き

ファイルの検索

一時ファイルの作成

ファイルに関する情報の取得

ディレクトリ操作

システム情報の取得

ファイルの使用

ファイルの作成とオープンの例

ファイルの読み書きとロックの例

一時ファイルの作成と使用の例

ファイルの検索とファイル属性の変更

ディレクトリやディレクトリ ツリーの変更の監視の例

ファイル ポインタの取得の例

ファイル関数

システムの構成

ボリュームとは、 ディレクトリやファイルを格納できるようにフォーマットされたハード ディスクやフロッピー ディスクなどの記憶デバイスです。各ボリュームには、 ルート ディレクトリがあります。ボリューム上のディレクトリやファイルは、 ルート ディレクトリから始まるツリー構造で組織化されています。各ディレクトリ エントリは、 ファイルやサブディレクトリの名前、 属性、 位置、 サイズを識別します。

大きなボリュームは、 複数の論理ボリューム (パーティションとも呼ばれます) に分割することもできます。ユーザーやオペレーティング システムには、 各パーティションが独立したボリュームのように見えます。

ファイル システムとは、 ボリューム上でのファイルの低レベルの組織化を行うオペレーティング システム ソフトウェアです。Windowsは、 次に示すファイル システムをサポートしています。

ファイル アロケーション テーブル (FAT)

ハイ パフォーマンス ファイル システム (HPFS)

NTファイル システム (NTFS)

ファイル システムの種類によって、 ボリューム上のファイル名の規約は異なり、 セキュリティや修復、 入出力 (I/O) の性能などのファイル システムの機能も異なります。ファイル システムは、 ボリュームごとに異なるものを使うことができます。

FAT HPFS NTFSファイル システムについて詳しくは、 ファイル システムの概要を参照してください。

ファイルのアクセス

ファイル関数が最初にボリュームにアクセスしたときや、 フロッピー ディスク ドライブにボリュームが挿入されたとき、 Windowsは、 そのボリュームを調べて、 適切なファイル システムを判断します。その後、 Windowsは、 そのファイル システムをサポートするデバイス ドライバによって、 ボリュームへのI/Oをすべて管理します。エラーが発生すると、 ドライバはWindowsに戻り、 Windowsはエラーをアプリケーションに返します。

Windowsのファイル関数によって、 ファイル システムにかかわらずファイルをアクセスできます。しかし、 使用しているファイル システムやオペレーティング システムによって、 利用可能な機能は異なります。たとえば、 CreateFile関数にはセキュリティ パラメータがありますが、 現在のバージョンのMS-DOSで動作するWindows用に作成されたアプリケーションではセキュリティは利用できません。

ファイルやディレクトリの作成、 オープン、 削除を行うWindowsファイル関数は、 ファイルやディレクトリを名前で識別します。ファイル関数は、 ほかのディレクトリやディスク ドライブのパスが明示的に指定されていなければ、 現在のディスク ドライブの現在のディレクトリでファイルやディスクの格納と検索を行います。

ファイル名の規約

各ファイル システムにはディレクトリ名やファイル名の構成要素の形式についてそれぞれ固有の規則がありますが、 名前の構成要素の組み合わせ方には、 どのファイル システムもしたがわなければならない一般的な規約があります。たとえば、 FATファイル システムでは、 ファイル名やディレクトリ名は8.3文字形式でなければなりません。HPFSNTFSでは、 名前は最大255文字です。しかし、 どのファイル システムでも、 パスを作成するときは、 円記号 (\) を使ってディレクトリ名やファイル名を区切ります。

アプリケーションがディレクトリやファイルの名前を作成したりユーザーが指定した名前を処理するときの一般的な規則には、 次のようなものがあります。

名前には現在のコード ページの文字を使ってください。しかし、 パス区切り文字やコード ポイントが0から31までの文字など、 ファイル システムが明示的に禁止している文字は使わないでください。名前には、 拡張文字セット (128から255) の文字を使うこともできます。

パスの構成要素を区切るには、 円記号 (\) やスラッシュ (/) を使ってください。これ以外の文字は、 パス区切り文字には使えません。

パスで現在のディレクトリを示すには、 ピリオド (.) をディレクトリ要素として使ってください。

パスで現在のディレクトリの親ディレクトリを示すには、 ピリオド2 (..) をディレクトリ要素として使ってください。

ディレクトリ名やファイル名の構成要素を区切るには、 ピリオド (.) を使ってください。

次に示す文字はWindowsで予約されているため、 ディレクトリ名やファイル名には使わないでください。

< > : " / \ |

ファイル名やディレクトリ名などにauxcon prnなどの予約語を使わないでください。

パスはNULLで終わる文字列として処理してください。パスの最大の長さはMAX_PATHです。

大文字小文字が区別されるかどうかを仮定しないでください。OSCAROscar oscarなどはすべて同じと考えてください。

上記の規則にしたがえば、 使用しているファイル システムにかかわらず、 有効なファイル名やディレクトリ名を作成できます。

Windows NT FAT パーティションでの長いファイル名について詳しくは、 Windows NTFATパーティション上の長いファイル名を参照してください。

ファイルの操作

ここでは、 Microsoft Win32(R) アプリケーション プログラミング インターフェイス (API) のファイル関数に提供されているファイルI/O操作とオペレーティング システム情報を説明します。

ファイルの作成とオープン

CreateFile関数は、 新しいファイルを作成したり、 既存のファイルをオープンします。この関数を使うときは、 ファイルに対して読み取り、 書き込み、 またはその両方のどれを行うかを指定してください。また、 ファイルが存在しなかったときの動作も指定してください。たとえば、 常にファイルを作成するように指定できます。この場合、 CreateFileは、 ファイルが存在しなければ作成し、 存在すれば上書きします。

また、 CreateFileには、 ファイルの読み書きの共有の方法を指定できます。共有されていないファイルは、 そのファイルを最初にオープンしたアプリケーションがファイルをクローズするまで、 最初にオープンしたアプリケーションやほかのアプリケーションからもう一度オープンすることはできません。

Windowsは、 オープンしたファイルや作成したファイルに、 「ファイル ハンドル」と呼ばれる一意な識別子を割り当てます。ファイル ハンドルは、 ファイルの読み書きやファイルの指定を行う関数の引数に指定します。ファイル ハンドルは、 ファイルをクローズするまで有効です。ハンドルが継承可能ならば、 アプリケーションは、 起動時に、 起動元のプロセスでオープンされているファイル ハンドルをすべて継承します。プロセスについて詳しくは、 プロセスとスレッドの概要を参照してください。

標準入力、 標準出力、 標準エラー ファイル ハンドルについて詳しくは、 文字モード サポートの概要を参照してください。

ハンドルを使ってファイルをアクセスする前に、 CreateFileの戻り値をチェックしてください。エラーが発生したときは、 GetLastError関数を使って拡張エラー情報を取得できます。

ファイルのクローズと削除

オペレーティング システムのリソースを効率的に使うため、 不要になったファイルは、 CloseHandle関数を使ってクローズしてください。アプリケーションが終了するときにファイルがオープンされていれば、 Windowsはそのファイルを自動的にクローズします。

ファイルを削除するには、 DeleteFile関数を使います。しかし、 ファイルを削除する前に必ずクローズしてください。

ファイルのコピーと移動

ファイルは、 コピーする前に、 必ずクローズするか読み取り用にオープンしてください。ファイルを書き込み用にオープンしているスレッドがあってはいけません。既存のファイルを新しいファイルにコピーするには、 CopyFile関数を使います。新しいファイルがすでに存在するときにCopyFileが失敗するかどうかを指定することもできます。

また、 ファイルを移動するときも、 まずクローズしなければなりません。MoveFile関数は、 既存のファイルを新しい位置にコピーしてから、 元のファイルを削除します。ファイルの名前を変更するためは、 この関数をよく使います。

ファイルの読み書き

オープンされているファイルには、 次に読み書きが行われるバイトの位置を示す「ファイル ポインタ」があります。ファイルを初めてオープンしたとき、 Windowsは、 ファイル ポインタをファイルの先頭に設定します。Windowsは、 バイトを読み書きするごとに、 ファイル ポインタを進めます。また、 アプリケーションがSetFilePointer関数を使ってファイル ポインタを移動することもできます。

ファイルを読み書きするには、 ReadFile関数やWriteFile関数を使います。これらの関数には、 対象とするオープンされているファイルのハンドルが必要です。ReadFileWriteFileは、 指定されたバイト数をファイル ポインタが示す位置に読み書きします。データは指定されたとおりに読み書きされます。関数はデータを書式化しません。

ファイル ポインタがファイルの終端に達したときにアプリケーションがファイルを読み取ろうとしてもエラーは発生しませんが、 バイトを読み取ることはできません。このため、 エラーが発生せずに0バイトを読み取ったときは、 ファイルの終端に達しています。

ファイルの長さを切り捨てたり拡張するには、 SetEndOfFile関数を使います。この関数は、 ファイルの終端 (EOF) をファイル ポインタの現在位置に設定します。WriteFile0バイトを指定しても何もしません。

通常、 アプリケーションがファイルに書き込むと、 Windowsは、 アプリケーションが書き込もうとするデータを内部バッファに集めて、 そのデータを定期的にディスクに書き込みます。

バッファの内容を強制的にディスクに書き込ませる (フラッシュするともいう) には、 FlushFileBuffers関数を使います。また、 書き込み操作で内部バッファをバイパスしてディスクに直接書き込むようにするには、 CreateFile関数を使ってファイルを作成したりオープンするときにフラグを設定します。

Windowsは、 ファイルをクローズするまで、 内部バッファの内容をディスクに自動的には書き込みません。ファイルをクローズする前にアプリケーションがデータを書き込むようにオペレーティング システムに指示しなければ、 キャッシュ アルゴリズムによって、 バッファをディスクに書き込むかどうかが決定されます。

ファイルのロックとロック解除

Windowsでは、 複数のアプリケーションが同じファイルをオープンして書き込むことができますが、 ほかのアプリケーションが書き込んでいる部分には書き込まないでください。ほかのアプリケーションとの干渉を避けるには、 ファイルの特定の部分を一時的にロックします。LockFile関数は、 ファイル内の指定されたバイト範囲をロックします。範囲は、 ファイルの現在の終端を超えていてもかまいません。ファイルの一部をロックすることによって、 ほかのプロセスはその領域を読み書きできないようになります。ほかのプロセスがロックした領域に対する読み書きは常に失敗します。領域のロックを解除するには、 UnlockFile関数を使います。ロックした領域は、 ファイルをクローズする前に、 すべてロック解除してください。

入出力の同期

「非同期入出力」とはI/Oの実行方法の1つで、 一部のI/O関数は、 I/O要求が処理待ち中でもすぐに戻ります。これによって、 アプリケーションは、 ほかの処理を続けながら、 I/O操作が完了するのを待つことができます。非同期I/Oは、 オーバーラップI/Oとも呼ばれます。

ReadFile関数やWriteFile関数には、 読み書き操作の前にファイル ポインタを設定する位置を示すOVERLAPPED構造体を指定します。読み書きするファイルのハンドルは、 FILE_FLAG_OVERLAPPEDフラグを指定してオープンしなければなりません。また、 OVERLAPPED構造体には、 WaitForSingleObject関数とWaitForMultipleObjects関数のどちらを使って待つのかを示すイベント ハンドルを設定します。

また、 ファイル ハンドルに対するI/O操作が完了するまで待機して、 操作を同期的に行うこともできますが、 これには十分な注意が必要です。I/O操作が開始されると、 オペレーティング システムは、 ファイル ハンドルを非シグナル状態に設定します。また、 I/O操作が完了すると、 オペレーティング システムは、 ファイル ハンドルをシグナル状態に設定します。このため、 アプリケーションが1つのファイル ハンドルに対して2つのI/O操作を開始して待機すると、 ハンドルがシグナル状態に設定されたときに、 どちらの操作が終了したのかがわからなくなります。1つのファイルに対して複数の非同期I/O操作を実行するときは、 ファイル ハンドルではなく、 各I/O操作のOVERLAPPED構造体のイベント ハンドルを基準にして待機してください。

ReadFileEx関数やWriteFileEx関数によって、 非同期I/O要求が完了したとき実行されるルーチンを指定できます。

同期について詳しくは、 同期の概要を参照してください。

ファイルの検索

特定のパターンに一致するファイル名を現在のディレクトリで検索するには、 FindFirstFile関数、 FindNextFile関数、 FindClose関数を使います。パターンは、 ワイルドカード文字を含む有効なファイル名でなければなりません。

FindFirstFileは、 FindNextFileが同じパターンのほかのファイルを検索するのに使うハンドルを作成します。どちらの関数も、 見つかったファイルに関する情報をWIN32_FIND_DATA構造体で返します。この情報には、 ファイル名、 サイズ、 属性、 時刻があります。FindClose関数は、 FindFirstFileが作成したハンドルを破棄します。

特定のパスのファイルを1つだけ検索するには、 SearchPath関数を使います。

一時ファイルの作成

一時ファイルの名前を作成するには、 GetTempFileName関数を使います。GetTempPath関数は、 一時ファイルを作成するディレクトリのパスを取得します。

ファイルに関する情報の取得

次の表に示すように、 ファイルには、 属性とよばれる10個の特性があります。

属性意味

FILE_ATTRIBUTE_ARCHIVE ファイルはアーカイブ ファイルです。このフラグは、 バックアップしたり削除するファイルをマークするのに使います。

FILE_ATTRIBUTE_DIRECTORY ファイルはディレクトリです。

FILE_ATTRIBUTE_HIDDEN ファイルは隠しファイルです。隠しファイルは通常のディレクトリ表示には表示されません。

FILE_ATTRIBUTE_NORMAL ファイルにはほかの属性は設定されていません。この属性は、 単独で使われているときだけ有効です。

FILE_ATTRIBUTE_READONLY ファイルは読み取り専用です。ファイルから読み取ることはできますが、 書き込んだり削除することはできません。

FILE_ATTRIBUTE_SYSTEM オペレーティング システム専用のファイルです。

FILE_ATTRIBUTE_TEMPORARY ファイルは一時的な記憶域として使われています。ファイルには、 必要なときだけ書き込みます。ファイルはすぐに削除されるため、 ファイルのデータのほとんどはメモリ内にあり、 メディアにはフラッシュされません。

FILE_ATTRIBUTE_ATOMIC_WRITE ファイルはアトミック書き込みファイルです。アプリケーションは、 アトミック書き込み方法を使ってファイルに書き込みます。書き込み操作でデータをメディアにフラッシュするときは、 その時点までの書き込み操作やファイル システム構造体もすべてフラッシュされます。これによって、 データを後で取得できるようになります。

FILE_ATTRIBUTE_XACTION_WRITE ファイルはトランザクション書き込みファイルです。アプリケーションは、 トランザクション書き込み方法を使ってファイルに書き込みます。トランザクション書き込みの場合、 データはすべてメディアに書き込まれるか、 まったく書き込まれないかのどちらかです。

ファイルの属性を取得または設定するには、 GetFileAttributes関数とSetFileAttributes関数を使います。しかし、 SetFileAttributesを使ってディレクトリの属性を設定することはできません。

GetFileType関数は、 ファイルの種類 (ディスク、 コンソールなどの文字ファイル、 パイプ、 不明など) を返します。GetFileSize関数は、 ファイルのサイズを返します。ファイルのフル パスを取得するには、 GetFullPathName関数を使います。

ファイルの作成日時、 最終変更日時、 最終アクセス日時を取得または設定するには、 GetFileTime関数とSetFileTime関数を使います。ファイル時刻について詳しくは、 時刻の概要を参照してください。

ディレクトリ操作

アプリケーションが新しいファイルを作成すると、 オペレーティング システムは、 そのファイルを指定されたディレクトリに追加します。各ディレクトリには、 ディスクの物理的な制限に達するまで、 いくつでもファイルを置くことができます。新しいディレクトリを作成したり、 既存のディレクトリを削除するには、 CreateDirectory関数やRemoveDirectory関数を使います。空でないディレクトリを削除することはできません。

アクティブなパスの終端にあるディレクトリは、 「現在のディレクトリ」と呼ばれます。特に指定しなければ、 アクティブなアプリケーションが起動したディレクトリが現在のディレクトリになります。現在のディレクトリを判断するには、 GetCurrentDirectory関数を使います。また、 現在のディレクトリを変更するには、 SetCurrentDirectory関数を使います。

FILE_FLAG_BACKUP_SEMANTICSフラグを設定してCreateFile関数CreateFileを呼び出すことでディレクトリ ハンドルを取得できます。関数によっては、 ファイル ハンドルの代わりにディレクトリ ハンドルを渡せるものもあります。

ディレクトリやそのサブディレクトリの内容を監視するには、 FindFirstChangeNotification関数、 FindNextChangeNotification関数、 FindCloseChangeNotification関数を使います。変更の通知の待機は、 ディレクトリやそのサブディレクトリに対する未処理の読み取り操作の待機と同じです。監視対象のディレクトリで何かが変更されると、 読み取り操作は完了します。たとえば、 上記の関数を使って、 監視対象のディレクトリ内のファイル名が変化するたびにディレクトリの表示を更新できます。

変更通知が発生する条件のセットを指定するには、 FindFirstChangeNotification関数を使います。変更通知条件には、 ファイル名、 ディレクトリ名、 属性、 ファイル サイズ、 最終書き込み時刻、 セキュリティがあります。また、 この関数は、 WaitForSingleObject関数やWaitForMultipleObjects関数を使って待機するためのハンドルを返します。条件が成立したら、 FindNextChangeNotificationを使って、 次の変更を待機するための通知ハンドルを取得できます。

FindCloseChangeNotification関数は、 通知ハンドルをクローズします。

システム情報の取得

Windowsには、 ファイル システムやオペレーティング システム、 ハードウェアに関する情報を取得するための関数がいくつか用意されています。

GetVolumeInformation関数は、 特定のボリュームのファイル システムに関する情報を取得します。この情報には、 ボリューム名、 ボリュームのシリアル番号、 ファイル システム名、 ファイル システム フラグ、 ファイル名の最大の長さなどがあります。

GetSystemDirectory関数とGetWindowsDirectory関数は、 それぞれ、 Windowsシステム ディレクトリとWindowsディレクトリのパスを取得します。

GetDiskFreeSpace関数は、 ディスクの構成情報を返します。この情報は、 セクタ当たりのバイト数、 クラスタ当たりのセクタ数、 未使用セクタ数、 総セクタ数です。

GetDriveType関数は、 指定されたディスク ドライブが参照するディスクの種類 (交換可能、 固定、 CD-ROM RAM、 ネットワーク ドライブなど) を返します。

GetLogicalDrives関数は、 オペレーティング システムに現在存在するドライブを返します。GetLogicalDriveStrings関数は、 オペレーティング システムに存在する各ドライブを示すNULLで終わる文字列を返します。ルート ディレクトリが必要なときは、 この文字列を使ってください。

ファイルの使用

Windowsファイル関数によって、 使用しているファイル システムにかかわらずファイルにアクセスできます。しかし、 利用可能な機能は、 使用しているオペレーティング システムによって異なります。特定の関数について知りたいときは、 その関数の説明を参照してください。

ファイルを操作する関数では、 ファイル名は現在のディレクトリに相対的に解釈されます。ファイル名がディスク名や円記号 (\) などのディレクトリ名区切り文字で始まっていなければ、 ファイル名は現在のディレクトリに相対的に解釈されます。ファイル名がディスク名で始まっているときは、 フル パス指定として解釈されます。

このトピックの例では、 次に示す処理の実行方法を示します。

ファイルの作成、 オープン、 クローズ、 削除

ファイルの読み書き

ファイルのロック、 ロック解除

ファイル ポインタの設定

一意な一時ファイル名の取得

ファイルの移動

ファイルの検索

ディレクトリの作成

ファイルのコピー

ファイルの属性の取得、 設定

ディレクトリやディレクトリ ツリーの変更の監視

ファイルの作成とオープンの例

新しいファイルを作成したり、 既存のファイルをオープンするには、 CreateFile関数を使います。この関数には、 ファイル名、 必要なアクセス、 共有モード、 作成指示、 属性を指定します。

次の例は、 現在のコンソールの入力バッファのハンドルを返します。

HANDLE hReadWriteInput;

hReadWriteInput = CreateFile("CONIN$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share with cmd. */
NULL,
OPEN_EXISTING,/* open already created console */
0,/* normal file open*/
NULL
);

コンソールについて詳しくは、 文字モード サポートの概要を参照してください。

次の例では、 CreateFileで既存のファイルをオープンしています。

HANDLE hFile;

hFile = CreateFile("MYFILE.TXT",/* open MYFILE.TXT*/
GENERIC_READ,/* open for reading*/
FILE_SHARE_READ,/* share for reading */
(LPSECURITY_ATTRIBUTES) NULL, /* no security*/
OPEN_EXISTING,/* existing file only */
FILE_ATTRIBUTE_NORMAL,/* normal file*/
(HANDLE) NULL); /* no attr. template */

if (hFile == INVALID_HANDLE_VALUE) {
ErrorHandler("Could not open file.");/* process error */
}

上記の例では、 MYFILE.TXTという名前のファイルが現在のディレクトリに存在するときだけ、 CreateFileは成功します。アプリケーションでは、 ハンドルを使ってファイルにアクセスする前に、 CreateFileの戻り値をチェックしてください。エラーが発生したときは、 GetLastError関数を使って拡張エラー情報を取得し、 適切な処理を行ってください。

ファイルを削除するには、 まずクローズしなければなりません。次の例は、 ファイルMYFILE.TXTをクローズして削除します。

CloseHandle(hFile);
DeleteFile("MYFILE.TXT");

次に示す例では、 CreateFileを使って新しいファイルを作成し、 書き込み用にオープンしています。

HANDLE hFile;

hFile = CreateFile("MYFILE.TXT",/* create MYFILE.TXT */
GENERIC_WRITE,/* open for writing*/
0,/* do not share*/
(LPSECURITY_ATTRIBUTES) NULL, /* no security*/
CREATE_ALWAYS,/* overwrite existing */
FILE_ATTRIBUTE_NORMAL |/* normal file*/
FILE_FLAG_OVERLAPPED,/* asynchronous I/O*/
(HANDLE) NULL);/* no attr. template*/
if (hFile == INVALID_HANDLE_VALUE) {
ErrorHandler("Could not open file."); /* process error*/
}

また、 (読み取り専用、 隠しファイル、 システム ファイルなどの) 標準属性のほかに、 4番目のパラメータとしてSECURITY_ATTRIBUTES構造体を指すポインタを指定することによって、 セキュリティ属性を指定できます。しかし、 セキュリティをオペレーティング システムがサポートしていなければ、 セキュリティシステムの指定は無効になります。

ファイルの読み書きとロックの例

ReadFile関数には、 読み取り用または読み書き用にオープンしたファイル ハンドルが必要です。ReadFileは、 指定されたバイト数を指定されたバッファにコピーします (ファイルの終端に達したときはそこで終了します)。この関数は、 4番目のパラメータが指す変数に、 実際に読み取ったバイト数を返します。

WriteFile関数には、 書き込み用または読み書き用にオープンしたファイル ハンドルが必要です。WriteFileは、 指定されたバイト数を指定されたファイルにコピーします (バッファの終端に達したときはそこで終了します)。この関数は、 4番目のパラメータが指す変数に、 実際に書き込んだバイト数を返します。

次の例は、 非同期I/Oの終了をコールバックを使って処理する方法を示しています。

完了ルーチン

VOID IoCompletionRoutine(DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
/* If an I/O error occurred, display the error and then exit. */

if (dwErrorCode) {
printf("FATAL I/O Error %ld I/O Context %lx.%lx\n",
dwErrorCode, lpOverlapped, lpOverlapped->hEvent);
ExitProcess(dwErrorCode);
}
LocalFree(lpOverlapped);
}

メイン スレッド

VOID IoWorkerThread(VOID)
{
HANDLE HandleVector[2];
DWORD CompletionStatus;
PIOREQUEST IoRequestPacket;
LPOVERLAPPED Overlapped;
BOOL IoOperationStatus;

HandleVector[0] = IoWorkerListLock;
HandleVector[1] = IoWorkerListSemaphore;

for(;;) {

/* Do an alertable wait on the handle vector. Both objects */
/* being signaled at the same time means there is an*/
/* I/O request in the queue, and the caller has exclusive*/
/* access to the queue.*/

CompletionStatus = WaitForMultipleObjectsEx(2, HandleVector,
TRUE, INFINITE, TRUE);

/* If the wait failed, error out. */

if (CompletionStatus == 0xFFFFFFFF) {
printf("FATAL WAIT ERROR %ld\n", GetLastError());
ExitProcess(1);
}
/* If an I/O completion occurred, wait for another*/
/* I/O request or I/O completion.*/

if (CompletionStatus != WAIT_IO_COMPLETION) {

/* Wait was satisfied. We now have exclusive ownership of*/
/* the I/O request queue, and there is something in the*/
/* queue. To insert something in the queue, the */
/* inserter gets the list lock (mutex), inserts an entry,*/
/* signals the list semaphore, and finally releases the*/
/* list lock.*/

IoRequestPacket = RemoveHeadList(&IoRequestList);

ReleaseMutex(IoWorkerListLock);

/* Allocate an overlapped structure. */

Overlapped = LocalAlloc(LMEM_ZEROINIT,
sizeof(OVERLAPPED));

if (!Overlapped) {
printf("FATAL allocation error\n");
ExitProcess(1);
}

Overlapped->Offset = IoRequestPacket->Offset;
Overlapped->OffsetHigh = IoRequestPacket->OffsetHigh;
Overlapped->hEvent =
IoRequestPacket->dwAdditionalIoContext;

if (IoRequestPacket->bRead) {
IoOperationStatus =
ReadFileEx(IoRequestPacket->hFile,
IoRequestPacket->lpBuffer,
IoRequestPacket->dwTransferCount,
Overlapped, IoCompletionRoutine);
}
else {
IoOperationStatus =
WriteFileEx(IoRequestPacket->hFile,
IoRequestPacket->lpBuffer,
IoRequestPacket->dwTransferCount,
Overlapped,
IoCompletionRoutine);
}

/* Test to see if I/O was queued successfully. */

if (!IoOperationStatus) {
printf("FATAL I/O Error %ld I/O Context %lx.%lx\n",
GetLastError(), Overlapped, Overlapped->hEvent);
ExitProcess(1);
}

/* The I/O queued successfully. Go back into the */
/* alertable wait for I/O completion or for*/
/* more I/O requests.*/

}
}
}

SetFilePointer関数は、 ファイルの先頭または終端、 ファイル ポインタの現在位置のいずれかに相対的に、 ファイル ポインタを指定されたバイト数だけ移動します。正のバイト数を指定すると、 SetFilePointerは、 ファイル ポインタをファイルの終端に向って移動します。負の値を指定すると、 ファイル ポインタをファイルの先頭に向って移動します。

次に示す例は、 ファイルをもう1つのファイルの終端に追加します。アプリケーションは、 CreateFileを使って2つのファイルをオープンします。ONE.TXTは読み取り用に、 TWO.TXTは書き込み用にオープンします。それから、 ReadFileWriteFileを使って4Kバイトのブロックを読み書きすることによって、 ONE.TXTの内容をTWO.TXTの終端に追加します。第2のファイルに書き込む前に、 SetFilePointerを使って第2のファイルのポインタをファイルの終端に設定し、 LockFileを使って書き込む領域をロックします。これによって、 書き込み処理中にほかのプロセスがその領域にアクセスできなくなります。書き込み操作が終了するごとに、 ロックした領域をUnlockFileでロック解除します。

HANDLE hFile;

HANDLE hAppend;

DWORDdwBytesRead, dwBytesWritten, dwPos;

char buff[4096];

/* Open the existing file. */

hFile = CreateFile("ONE.TXT",/* open ONE.TXT*/
GENERIC_READ,/* open for reading*/
0,/* do not share*/
(LPSECURITY_ATTRIBUTES) NULL, /* no security*/
OPEN_EXISTING,/* existing file only */
FILE_ATTRIBUTE_NORMAL,/* normal file*/
(HANDLE) NULL);/* no attr. template*/
if (hFile == INVALID_HANDLE_VALUE) {
ErrorHandler("Could not open ONE.");/* process error */
}

/*
* Open the existing file or, if the file doesn't exist,
* create new file.
*/

hAppend = CreateFile("TWO.TXT",/* open TWO.TXT*/
GENERIC_WRITE,/* open for writing*/
0,/* do not share*/
(LPSECURITY_ATTRIBUTES) NULL, /* no security*/
OPEN_ALWAYS,/* open or create*/
FILE_ATTRIBUTE_NORMAL,/* normal file*/
(HANDLE) NULL);/* no attr. template*/
if (hAppend == INVALID_HANDLE_VALUE) {
ErrorHandler("Could not open TWO.");/* process error */
}

/*
* Append the first file to the end of the second file.
* Lock the second file to prevent another process from
* accessing it while writing to it. Unlock the
* file when writing is finished.
*/

do {
if (ReadFile(hFile, (LPSTR) buff, 4096, &dwBytesRead, NULL)) {
dwPos = SetFilePointer(hAppend, 0, (LPLONG) NULL, FILE_END);
LockFile(hAppend, dwPos, 0, dwPos + dwBytesRead, 0);
WriteFile(hAppend, (LPSTR) buff, dwBytesRead,
&dwBytesWritten, NULL);
UnlockFile(hAppend, dwPos, 0, dwPos + dwBytesRead, 0);
}
} while (dwBytesRead == 4096);

/* Close both files. */

CloseHandle(hFile);
CloseHandle(hAppend);

一時ファイルの作成と使用の例

次に示す例は、 ファイルをほかのファイルにコピーします。第2のファイルは、 第1のファイルを大文字に変換したものです。

アプリケーションは、 CreateFileを使ってファイルORIGINAL.TXTをオープンします。それから、 GetTempFileName関数を使って一時ファイル名を取得し、 CreateFileを使って一時ファイルを作成します。4Kバイトのブロックをバッファに読み取って大文字に変換し、 そのバッファを一時ファイルに書き込みます。ORIGINAL.TXTの内容をすべて一時ファイルに書き込んだら、 ORIGINAL.TXTと一時ファイルをクローズし、 MoveFile関数を使って一時ファイルの名前をALLCAPS.TXTに変更します。

HANDLE hFile;

HANDLE hTempFile;

DWORDdwBytesRead, dwBytesWritten, dwPos;

char szTempName[MAX_PATH];

char buffer[4096];

/* Open the existing file. */

hFile = CreateFile("ORIGINAL.TXT",/* filename*/
GENERIC_READ,/* open for reading*/
0,/* do not share*/
(LPSECURITY_ATTRIBUTES) NULL, /* no security*/
OPEN_EXISTING,/* existing file only */
FILE_ATTRIBUTE_NORMAL,/* normal file*/
(HANDLE) NULL);/* no attr. template*/
if (hFile == INVALID_HANDLE_VALUE) {
ErrorHandler("Could not open file."); /* process err. on fail*/
}

/* Create a temporary file. */

GetTempFileName("\\TEMP", /* dir. for temp. files */
"NEW",/* temp. filename prefix*/
0,/* create unique name w/ sys. time */
(LPTSTR) szTempName); /* buffer for name*/
hTempFile = CreateFile((LPTSTR) szTempName,/* filename*/
GENERIC_READ | GENERIC_WRITE, /* open for read-write*/
0,/* do not share */
(LPSECURITY_ATTRIBUTES) NULL, /* no security*/
CREATE_ALWAYS,/* overwrite existing*/
FILE_ATTRIBUTE_NORMAL, /* normal file*/
(HANDLE) NULL);/* no attr. template*/
if (hTempFile == INVALID_HANDLE_VALUE) {
ErrorHandler("Could not create temporary file.");
}

/*
* Read 4K blocks to the buffer.
* Change all characters in the buffer to uppercase.
* Write the buffer to the temporary file.
*/

do {
if (ReadFile(hFile, (LPSTR) buffer, 4096,
&dwBytesRead, NULL)) {

CharUpperBuff((LPTSTR) buffer, dwBytesRead);

WriteFile(hTempFile, (LPSTR) buffer, dwBytesRead,
&dwBytesWritten, NULL);
}
} while (dwBytesRead == 4096);

/* Close both files. */

CloseHandle(hFile);
CloseHandle(hTempFile);

/* Move the temporary file to the new text file. */

if (!MoveFile(szTempName, "ALLCAPS.TXT")) {
ErrorHandler("Could not move temp. file.");
}

ファイルの検索とファイル属性の変更

次の例は、 現在のディレクトリのすべてのテキスト ファイルを\TEXTROという名前の読み取り専用ファイルのディレクトリにコピーします。必要ならば、 新しいディレクトリのファイルを読み取り専用に変更します。

アプリケーションは、 GetCurrentDirectory関数を使って現在のディレクトリのパスを取得します。このパスは、 \TEXTROディレクトリに移った後で現在のディレクトリに戻るときにも使われます。

それから、 CreateDirectory関数を使って、 \TEXTROディレクトリを作成します。

次に、 FindFirstFile関数とFindNextFile関数を使って、 .TXTファイルを現在のディレクトリで検索し、 各.TXTファイルを\TEXTROディレクトリにコピーします。ファイルをコピーしたら、 GetFileAttributes関数を使って、 ファイルが読み取り専用かどうか判断します。ファイルが読み取り専用ならば、 ディレクトリを\TEXTROに変更し、 SetFileAttributes関数を使って、 コピーしたファイルを読み取り専用に変更します。

現在のディレクトリの.TXTファイルをすべてコピーしたら、 FindClose関数を使って検索ハンドルをクローズします。

WIN32_FIND_DATA FileData;
HANDLE hSearch;
DWORD dwAttrs;
char szDirPath[] = "c:\\TEXTRO\\";
char szNewPath[MAX_PATH];
char szHome[MAX_PATH];

BOOL fFinished = FALSE;

/* Create a new directory. */

if (!CreateDirectory(szDirPath, NULL)) {
ErrorHandler("Couldn't create new directory.");
}

/* Start searching for .TXT files in the current directory. */

hSearch = FindFirstFile("*.TXT", &FileData);
if (hSearch == INVALID_HANDLE_VALUE) {
ErrorHandler("No .TXT files found.");
}

/*
* Copy each .TXT file to the new directory
* and change to read only, if not already.
*/

while (!fFinished) {
lstrcpy(szNewPath, szDirPath);
lstrcat(szNewPath, FileData.cFileName);
if (CopyFile(FileData.cFileName, szNewPath, FALSE)) {
dwAttrs = GetFileAttributes(FileData.cFileName);
if (!(dwAttrs & FILE_ATTRIBUTE_READONLY)) {
SetFileAttributes(szNewPath,
dwAttrs | FILE_ATTRIBUTE_READONLY);
}
}
else {
ErrorHandler("Couldn't copy file.");
}

if (!FindNextFile(hSearch, &FileData))
if (GetLastError() == ERROR_NO_MORE_FILES) {
MessageBox(hwnd, "No more .TXT files.",
"Search completed.", MB_OK);
fFinished = TRUE;
}
else {
ErrorHandler("Couldn't find next file.");
}
}

/* Close the search handle. */

if (!FindClose(hSearch)) {
ErrorHandler("Couldn't close search handle.");
}

ディレクトリやディレクトリ ツリーの変更の監視の例

次の例は、 C:\から始まるディレクトリ ツリーのディレクトリ名の変更を監視します。また、 C:\WINDOWSディレクトリのファイル名の変更も監視します。

この例では、 FindFirstChangeNotification関数を使って通知ハンドルを2つ作成し、 WaitForMultipleObjects関数を使ってハンドルを待機します。C:\から始まるツリーでディレクトリが作成されたり削除されると、 ディレクトリ ツリー全体を更新します。C:\WINDOWSディレクトリでファイルが作成されたり削除されると、 WINDOWSディレクトリを更新します。FindNextChangeNotification関数は、 変更を処理したときに変更通知を再開します。

DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];

/*
* Watch the C:\WINDOWS directory for file creation and
* deletion.
*/

dwChangeHandles[0] = FindFirstChangeNotification(
"C:\\WINDOWS",/* directory to watch*/
FALSE,/* do not watch the subtree */
FILE_NOTIFY_CHANGE_FILE_NAME); /* watch filename changes*/

if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());

/*
* Watch the C:\ subtree for directory creation and
* deletion.
*/

dwChangeHandles[1] = FindFirstChangeNotification(
"C:\\",/* directory to watch*/
TRUE, /* watch the subtree*/
FILE_NOTIFY_CHANGE_DIR_NAME);/* watch dir. name changes */

if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());

/*
* Change notification is set. Now wait on both notification
* handles and refresh accordingly.
*/

while (TRUE) {

/* Wait for notification. */

dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
FALSE, INFINITE);

switch (dwWaitStatus) {

case WAIT_OBJECT_0:

/*
* A file was created or deleted in C:\WINDOWS.
* Refresh this directory and restart the
* change notification. RefreshDirectory is an
* application-defined function.
*/

RefreshDirectory("C:\\WINDOWS")
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE)
ExitProcess(GetLastError());
break;

case WAIT_OBJECT_0 + 1:

/*
* A directory was created or deleted in C:\.
* Refresh the directory tree and restart the
* change notification. RefreshTree is an
* application-defined function.
*/

RefreshTree("C:\\");
if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE)
ExitProcess(GetLastError());
break;

default:
ExitProcess(GetLastError());
}
}

ファイル ポインタの取得の例

次の例は、 hFileが示すファイルのファイル ポインタの現在位置を取得します。

HANDLE hFile;


DWORD dwCurrentFilePosition;

dwCurrentFilePosition = SetFilePointer(
hFile, /* must have GENERIC_READ and/or GENERIC_WRITE*/
0,/* do not move pointer*/
NULL,/* hFile is not large enough to need this pointer */
FILE_CURRENT);/* provides offset from current position */

ファイル関数

ファイルに関する関数を次に示します。

_hread

_hwrite

_lclose

_lcreat

_llseek

_lopen

_lread

_lwrite

AreFileApisANSI

CloseHandle

CopyFile

CreateDirectory

CreateDirectoryEx

CreateFile

CreateIoCompletionPort

DefineDosDevice

DeleteFile

FileIOCompletionRoutine

FindClose

FindCloseChangeNotification

FindFirstChangeNotification

FindFirstFile

FindNextChangeNotification

FindNextFile

FlushFileBuffers

GetBinaryType

GetCurrentDirectory

GetDiskFreeSpace

GetDriveType

GetFileAttributes

GetFileInformationByHandle

GetFileSize

GetFileType

GetFullPathName

GetLogicalDrives

GetLogicalDriveStrings

GetQueuedCompletionStatus

GetShortPathName

GetTempFileName

GetTempPath

GetVolumeInformation

LockFile

LockFileEx

MoveFile

MoveFileEx

OpenFile

QueryDosDevice

ReadFile

ReadFileEx

RemoveDirectory

SearchPath

SetCurrentDirectory

SetEndOfFile

SetFileApisToANSI

SetFileApisToOEM

SetFileAttributes

SetFilePointer

SetHandleCount

SetVolumeLabel

UnlockFile

UnlockFileEx

WriteFile

WriteFileEx

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします
inserted by FC2 system