SetFilePointer

https://msdn.microsoft.com/ja-jp/library/cc428944.aspx https://msdn.microsoft.com/ja-jp/library/ms682530.aspx https://msdn.microsoft.com/ja-jp/library/ms684266.aspx https://msdn.microsoft.com/ja-jp/library/cc428944.aspx https://msdn.microsoft.com/ja-jp/library/aa365564.aspx

開いているファイルのファイルポインタを移動します。

この関数は、ファイルポインタを 2 個の DWORD 値に分けて格納します。1 個の DWORD 値に格納できないファイルポインタ(2GB を超えるファイルに適用)をより簡単に扱うには、SetFilePointerEx 関数を使ってください。

DWORD SetFilePointer(
  HANDLE hFile,                // ファイルのハンドル
  LONG lDistanceToMove,        // ポインタを移動するべきバイト数
  PLONG lpDistanceToMoveHigh,  // ポインタを移動するべきバイト数
  DWORD dwMoveMethod           // 開始点
);

パラメータ

hFile
ファイルポインタを移動するべきファイルのハンドルを指定します。このハンドルは、GENERIC_READ または GENERIC_WRITE アクセス権を指定して作成したものでなければなりません。
lDistanceToMove
ファイルポインタの移動バイト数を保持している、符号付きの下位(low-order)32 ビットの値を指定します。lpDistanceToMoveHigh パラメータで NULL 以外の値を指定すると、lpDistanceToMoveHigh lpDistanceToMove の 2 個のパラメータを組み合わせて 1 個の符号付き 64 ビット値を形成して、移動バイト数を指定します。lpDistanceToMoveHigh が NULL の場合、lpDistanceToMove は 1 個の符号付き 32 ビット値として機能します。lpDistanceToMoveHigh で正の値を指定するとファイルの前方(ファイルの終わりへ向かって)移動し、負の値を指定すると後方(ファイルの先頭へ向かって)移動します。
lpDistanceToMoveHigh
移動バイト数を表す符号付き 64 ビットのうち、上位(high-order)32 ビットの値へのポインタを指定します。上位 32 ビットが必要ない場合(ファイルの大きさが 2GB 以内)、このパラメータで NULL を指定できます。NULL 以外の値を指定し、関数が成功した場合、このパラメータは、ファイルポインタの新しい位置を表す値の上位 DWORD を受け取ります。詳細については、この関数の「解説」を参照してください。

Windows 95/98:lpDistanceToMoveHigh パラメータで NULL 以外の値を指定する場合、0 と -1 のどちらかを指定しなければなりません。これは、lDistanceToMove パラメータの符号拡張であり、lDistanceToMove パラメータ単独で、2GB ではなく 4GB の大きさを表せるようになります。それ以外の値は拒否されます。

dwMoveMethod
ファイルポインタを移動するための開始点(基準点)を指定します。次の値のいずれかを指定します。
意味
FILE_BEGIN開始点は 0、つまりファイルの先頭です。
FILE_CURRENT開始点は、ファイルポインタの現在の位置です。
FILE_END開始点は、ファイルの終わり(EOF)です。

戻り値

lpDistanceToMoveHigh パラメータで NULL を指定した場合、関数が成功すると、新しいファイルポインタの下位 DWORD が返ります。また、lpDistanceToMoveHigh パラメータで NULL 以外の値を指定した場合、関数が成功すると、新しいファイルポインタの下位 DWORD が返り、そのパラメータが指す LONG 値に、新しいファイルポインタの上位 DWORD が格納されます。

lpDistanceToMoveHigh パラメータが NULL の場合、関数が失敗すると、INVALID_SET_FILE_POINTER が返ります。拡張エラー情報を取得するには、 関数を使います。

lpDistanceToMoveHigh パラメータが NULL 以外の場合、関数が失敗すると、INVALID_SET_FILE_POINTER が返ります。ただし、INVALID_SET_FILE_POINTER に相当する数値は新しいファイルポインタの下位 DWORD として有効な値なので、GetLastError 関数を呼び出してエラーが発生したかどうかをチェックしなければなりません。エラーが発生していた場合、GetLastError 関数は NO_ERROR 以外の値を返します。この点をチェックするサンプルコードについては、この関数の「解説」を参照してください。

新しいファイルポインタの値が負の数値になる場合、この関数は失敗し、GetLastError は ERROR_NEGATIVE_SEEK を返します。

解説

パイプや通信デバイスなど、シーク機構を持たないデバイスのハンドルを指定して SetFilePointer 関数を使うことはできません。ファイルの種類を調べるには、GetFileType 関数を使います。

ファイルポインタの現在の位置を調べる方法については、MSDN ライブラリの「」を参照してください。

マルチスレッドのアプリケーションでファイルポインタの位置を設定するときは、十分に注意してください。共有リソースへのアクセスを同期化する必要があります。たとえば、1 つのアプリケーションの複数のスレッドが 1 個のファイルハンドルを共有していて、あるスレッドがファイルポインタの位置を更新してファイルを読み取ろうとしている場合は、クリティカルセクションやミューテックス(mutually exclusive;相互排他)を使って一連の操作を保護してください。これらのオブジェクトの詳細については、MSDN ライブラリの「」と「」を参照してください。

hFile パラメータで、FILE_FLAG_NO_BUFFERING を指定して開いたファイルハンドルを指している場合、アプリケーションはセクタ整列された位置へのみファイルポインタを移動できます。セクタ整列された位置とは、ボリュームのセクタサイズの整数倍の位置を意味します。アプリケーションは、GetDiskFreeSpace 関数を呼び出して、ボリュームのセクタサイズを取得できます。hFile パラメータで FILE_FLAG_NO_BUFFERING を指定して開いたハンドルを指定し、アプリケーションが SetFilePointer 関数を呼び出す際に指定した移動バイト数と開始点の組み合わせが、セクタ整列された位置とは異なっている場合、この関数は失敗し、GetLastError は ERROR_INVALID_PARAMETER を返します。

ファイルの終わり(EOF)を超える位置にファイルポインタを設定してもエラーにならないことに注意してください。ただし、SetEndOfFileWriteFileWriteFileEx いずれかの関数を呼び出すまでは、ファイルのサイズは増加しません。書き込み操作を行うと、ファイルポインタの位置に、書き込まれたバッファのサイズを足した位置が新しいファイルの終わりになります。ファイルはその位置まで拡張されますが、元の EOF から新しい EOF までの領域は(実際に書き込みが行われた領域を除き)初期化されません。

lpDistanceToMoveHigh パラメータに NULL 以外の値を指定した場合、INVALID_SET_FILE_POINTER が返ることがあります。この場合、アプリケーションは 関数を呼び出して、関数が成功したか失敗したかを判断しなければなりません。次のサンプルコードは、この判定方法を示します。

// 状況 1:lpDistanceToMoveHigh == NULL

// を指定してこの関数を呼び出した場合。

// hFile のファイルポインタをある程度移動しようとする。

dwPtr = SetFilePointer (hFile, lDistance, NULL, FILE_BEGIN) ;

if (dwPtr == INVALID_SET_FILE_POINTER) // 失敗したかどうかテストする。

{

    // エラーコードを取得する。

    dwError = GetLastError() ;

    // エラーを処理する。

    // . . .

} // エラーハンドラの終わり。

//

// 状況 2:lpDistanceToMoveHigh != NULL

// を指定してこの関数を呼び出した場合。

// hFile のファイルポインタを非常に大きく(2GB 以上)移動しようとする。

dwPtrLow = SetFilePointer (hFile, lDistLow, & lDistHigh, FILE_BEGIN) ;

// 失敗したかどうかテストする。

if (dwPtrLow == INVALID_SET_FILE_POINTER && (dwError = GetLastError()) != NO_ERROR)

{

    // エラーを処理する。

    // . . .

} // エラーハンドラの終わり。

非常に大きなファイル(2GB 以上)を操作する場合に、lpDistanceToMoveHigh パラメータを使います。このパラメータで NULL を設定すると、lDistanceToMove パラメータの最大値は 2^31–2、つまり 2GB より 2 バイト小さい値になります。2^32(4GB)ではなく 2GB なのは、すべてのファイルポインタの値が符号付きであることが原因です。そのため、ファイルがこのサイズを超える可能性がほんのわずかでも存在する場合、そのファイルを非常に大きなファイルとして扱い、64 ビットのファイルポインタを使って作業するべきです。NTFS の「」(ファイル圧縮)と「」(スパースファイル)の各機能を使うと(これらの詳細については MSDN ライブラリを参照してください)、ボリュームが十分大きくない場合でも、ボリュームよりある程度大きいファイルを格納できます。

lpDistanceToMoveHigh が NULL ではない場合、lpDistanceToMoveHigh lDistanceToMove は 1 個の符号付き 64 ビット値を形成します。lDistanceToMove パラメータは下位 32 ビット値、lpDistanceToMoveHigh は上位 32 ビット値として扱われます。したがって、lpDistanceToMoveHigh lDistanceToMove の符号拡張の役割を果たします。

0~2GB の範囲でファイルポインタを移動する場合、lpDistanceToMoveHigh は NULL、つまり lpDistanceToMove の符号拡張でかまいません。移動バイト数が 2GB を超える場合、lpDistanceToMoveHigh lDistanceToMove を組み合わせて、1 個の 64 ビット値として扱います。たとえば、2GB~4GB の範囲でファイルポインタを移動するには、lDistanceToMoveHigh を 0 に設定するか(正の符号なので前方へ移動)、-1 に設定して lDistanceToMove の負の符号拡張の役割(この場合は後方へ移動)を割り当てます。

64 ビットのファイルポインタを使って作業する場合、1 個の LONG 型整数を宣言し、その変数を 64 ビットファイルポインタの上位 32 ビットとして扱い、lpDistanceToMoveHigh パラメータでその変数のアドレスを指定することが考えられます。これは、2 個の異なった変数を 1 個の論理単位として扱う必要があることを意味しますが、間違いが起こりやすくなるのは事実です。この問題を改善するには、LARGE_INTEGER 構造体を使って 1 個の 64 ビット値を作成し、この構造体の適切な要素に 2 個の 32 ビット値を指定します。

考え方としては、上記の概念を 1 つの関数に実装し、SetFilePointer の直接のインターフェイスを隠蔽した方が、簡単かつ明快な設計になります。このような実装を行うには、次のサンプルコードを参考にしてください。

__int64 myFileSeek (HANDLE hf, __int64 distance, DWORD MoveMethod)

{

   LARGE_INTEGER li;

   li.QuadPart = distance;

   li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);

   if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)

   {

      li.QuadPart = -1;

   }

   return li.QuadPart;

}

注意  SetFilePointer 関数を使って、ファイルの長さを判断することもできます。この場合、dwMoveMethod パラメータで FILE_END を指定し、位置 0(ファイルの先頭)への移動を行います。返されたファイルオフセットは、ファイルの長さに相当します。しかし、この方法には望ましくない副作用もあり、たとえば現在のファイルポインタを保存するのを忘れる可能性があります。もちろん、対策として、ファイルポインタを移動する前に現在の位置を保存しておくこともできますが、面倒なのは事実です。代わりに、GetFileSize 関数を使う方が簡単かつ安全です。

SetFilePointer 関数を使って、ファイルポインタの現在の位置を問い合わせることもできます。このような使い方をするには、開始点として FILE_CURRENT を指定し、移動バイト数として 0 を指定してください。

MAPI:詳細については、MSDN ライブラリの「」を参照してください。

対応情報

Windows NT/2000:Windows NT 3.1 以降
Windows 95/98:Windows 95 以降
ヘッダー:Winbase.h 内で宣言、Windows.h をインクルード
インポートライブラリ:Kernel32.lib を使用

参照

GetDiskFreeSpace, GetFileSize, GetFileType, ReadFile, ReadFileEx, SetEndOfFile, SetFilePointerEx, WriteFile, WriteFileEx

表示: