今回から、ファイルのオーバーラップについてやります。ファイルの読み書きに時間がかかる時、これが終了するまで他の作業が できないのでは、困ります。このような場合、オーバーラップを利用するとになります。
これには、win32のAPI関数を利用します。
CreateFile, ReadFile, WriteFile関数については、すでにSDK編で解説があります。
オーバーラップI/Oを行うには、CreateFile関数の第3引数をFILE_SHARE_READ | FILE_SHARE_WRITEにします。
第6引数をFILE_FLAG_OVERLAPPEDにします。
これで、ファイルをオープンします。
関数が失敗すると、INVALID_HANDLE_VALUEが返されます。
他のスレッドや、プロセスが使用中の場合、でもFILE_SHARE_***で読み書きしている場合はエラーになりません。
さて、次にReadFile関数で読み出します。
この時、第5引数にOVERLAPPED構造体へのポインタを指定します。
OVERLAPPED構造体は次のように定義されています。
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
Internalや、InternalHighは内部的に予約済みです。Offsetには、ReadFileやWriteFile関数のオフセットを指定します。
OffsetHighにはオフセットの上位WORD値を指定します。
hEventには、イベントハンドルを指定します。
ReadFile関数は読み取りが完了する前に制御を返すことがあります。
これにより、ReadFileに時間がかかる場合も、他の仕事をすることができます。
読み取り前に制御が返された時、この関数はFALSEを返します。
すぐに、GetLastError関数を呼び出すと、ERROR_IO_PENDINGが返されます。
WriteFile関数も同様に扱います。
さて、ペンディング中はGetOverlappedResult関数で待ちます。
BOOL GetOverlappedResult( HANDLE hFile, // ファイル、パイプ、通信デバイスのハンドル LPOVERLAPPED lpOverlapped, // オーバーラップ構造体 LPDWORD lpNumberOfBytesTransferred, // 転送されたバイト数 BOOL bWait // 待機オプション );bWaitにTRUEを指定すると、オーバーラップ操作が完了するまで待機します。
では、サンプルを見てみましょう。
/* overlap01.c */
#define MYFILE "c:\\test.txt"
#include <stdio.h>
#include <windows.h>
int main()
{
HANDLE hFile, hEvent;
OVERLAPPED ovl;
BOOL bRet, bLError;
char szBuf[64];
DWORD dwWritten;
strcpy(szBuf, "テスト書き込みです");
hEvent = CreateEvent(NULL, FALSE, FALSE, "olp");
hFile = CreateFile(MYFILE, GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("ファイルのオープンに失敗しました\n");
return -1;
}
memset(&ovl, 0, sizeof(OVERLAPPED));
ovl.hEvent = hEvent;
bRet = WriteFile(hFile, szBuf, (DWORD)strlen(szBuf), &dwWritten, &ovl);
if (!bRet) {
bLError = GetLastError();
if (bLError == ERROR_IO_PENDING) {
GetOverlappedResult(hFile, &ovl, &dwWritten, TRUE);
} else {
printf("エラーです");
CloseHandle(hFile);
CloseHandle(hEvent);
return -2;
}
}
CloseHandle(hFile);
CloseHandle(hEvent);
return 0;
}
Cドライブのルートにtest.txtと言うファイルを用意しておきます。プログラムを実行すると、このファイルに「テスト書き込みです」と書き込まれます。
次回から、もう少し実際的な状態を作ってみます。
Update Dec/06/2004 By Y.Kumei