Win32APIのReadFile関数の仕様で不明瞭な点がいくつかあるのですが

解決


michi  2006-10-15 23:31:40  No: 63331

ReadFileにてファイルの同期読み込みを行うとき、

> 戻り値が 0 以外で、実際に読み取ったバイト数が 0 の場合、読み取り操作を開始する時点でファイルポインタがファイルの終わり(EOF)を超えていたことを示します。
これは分かるのですが、

> 同期の読み取り操作を行っていて、ファイルの終わりに達した場合、ReadFile 関数は 0 以外の値(TRUE)を返し、*lpNumberOfBytesRead を 0 に設定します。
これはつまり、同期の読み取り操作を行っていてファイルの終わりに達した場合はどれだけ、読み込んだのか分からないということになりますよね。

だから例えば、ファイルをサイズのチェックもせずにただひたすら先頭から末尾まで読み込んでいくようなプログラムは、最後に読み込んだデータのどこまでを使っていいのか分からなくなると思うのですが、ドキュメントの解釈あってるでしょうか?

MSDN
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpfileio/html/_win32_readfile.asp


YuO  2006-10-15 23:49:25  No: 63332

なんで日本語版がそのような記述になっているのかはわかりませんが,英語版にそのような記述はありません。
http://msdn.microsoft.com/library/en-us/fileio/fs/readfile.asp

*lpNubmerOfBytesReadが0を返した時点で読み取り終了でよいことになります。


michi  2006-10-16 01:47:33  No: 63333

YuOさん、レスありがとうございます。

上の引用に対応する英語版のドキュメントは

> If the return value is nonzero and the number of bytes read is 0 (zero), the file pointer is beyond the current end of the file at the time of the read operation.

> When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets *lpNumberOfBytesRead to 0 (zero).

になると思いますが、日本語版と同じ意味だと思うのですが...う〜ん、英語にそれほど自信はないですけど、間違ってますでしょうか?


tetrapod  2006-10-16 02:07:13  No: 63334

まあ実験すればわかる話なのではあるが
15 byte の「普通のファイル」を 10 byte づつ読み込むと
1回目:10 2回目:5 3回目:0
となるわけだ。いずれも ReadFile の返却値は非0

pipe や Comm などだと違う結果になりうるよん


michi  2006-10-16 02:47:04  No: 63335

tetrapodさん、レスありがとうございます。

さっそく今、下記のプログラムを実行してみたところ

int _tmain(int argc,LPCTSTR argv[])
{
    ::_tsetlocale(LC_ALL,_T(""));
  
    HANDLE  hFile;
  
    //開く
    if((hFile=::CreateFile(
        _T("test.data"),  //テスト用ファイル(先頭から0x01,0x02...0x09と9byteデータが入っている)
        GENERIC_READ,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL)) == INVALID_HANDLE_VALUE)
    {
        ::_putts(_T("Failed to open the file."));
        return 0;
    }
  
    //読み込む
    DWORD  data;
    DWORD  bytesRead;
    BOOL  result;
    DWORD  errorCode;
    for(unsigned int count=0;count<4;count++)
    {
        result  =::ReadFile(
                    hFile,
                    &data,
                    sizeof(data),
                    &bytesRead,
                    NULL
                );
        errorCode =::GetLastError();
        
        ::_tprintf(
            _T("-------------------------\n")
            _T("data       :%#010x\n")
            _T("bytesRead  :%u\n")
            _T("result     :%s\n")
            _T("errorCode  :%u\n"),
            data,
            bytesRead,
            (result == TRUE)?_T("TRUE"):_T("FALSE"),
            errorCode
        );
  
    }
  
    //閉じる
    ::CloseHandle(hFile);
  
    return 0;
}

実行結果は

-------------------------
data       :0x04030201
bytesRead  :4
result     :TRUE
errorCode  :0
-------------------------
data       :0x08070605
bytesRead  :4
result     :TRUE
errorCode  :0
-------------------------
data       :0x08070609
bytesRead  :1
result     :TRUE
errorCode  :0
-------------------------
data       :0x08070609
bytesRead  :0
result     :TRUE
errorCode  :0

となりました。
ドキュメントに書いてあるわけではありませんが、

(戻り値がTRUE) && (*lpNumberOfBytesRead < nNumberOfBytesToRead)で
ファイルが終端に達した。*lpNumberOfBytesReadに実際に読み取れたバイト数が入る。

(戻り値がTRUE) && (*lpNumberOfBytesRead == 0)で
すでに終端に達している、もしくは超えている。

という解釈でいこうと思います。


michi  2006-10-16 02:50:40  No: 63336

YuOさん,tetrapodさん

ありがとうございました。


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加