The Windows File Management 25

 

 

 

 

 

Testing for the End of a File Program Example

 

The ReadFile() function checks for the end-of-file condition (eof) differently for synchronous and asynchronous read operations. When a synchronous read operation gets to the end of a file, ReadFile() returns TRUE and sets the variable pointed to by the lpNumberOfBytesRead parameter to zero. An asynchronous read operation can encounter the end of a file during the initiating call to ReadFile() or during subsequent asynchronous operations if the file pointer is programmatically advanced beyond the end of the file. The following C++ code snippet shows how to test for the end of a file during a synchronous read operation.

 

// Attempt a synchronous read operation.

bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL);

 

// Check for eof.

if (bResult &&  nBytesRead == 0)

{

    // at the end of the file

}

 

The test for end-of-file during an asynchronous read operation is slightly more involved than for a similar synchronous read operation. The end-of-file indicator for asynchronous read operations is when GetOverlappedResult() returns FALSE and GetLastError() returns ERROR_HANDLE_EOF. The following C/C++ example shows how to test for the end of file during an asynchronous read operation.

Create a new empty Win32 console application project. Give a suitable project name and change the project location if needed.

Then, add the source file and give it a suitable name.

Next, add the following source code.

 

#include <windows.h>

#include <stdio.h>

 

#define BUF_SIZE 100

 

// Routine Description: Retrieve the system error message for the last-error code

LPCTSTR ErrorMessage(DWORD error)

{

      LPVOID lpMsgBuf;

 

    FormatMessage(

        FORMAT_MESSAGE_ALLOCATE_BUFFER |

        FORMAT_MESSAGE_FROM_SYSTEM |

        FORMAT_MESSAGE_IGNORE_INSERTS,

        NULL,

        error,

        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

        (LPTSTR) &lpMsgBuf,

        0, NULL );

 

    return((LPCTSTR)lpMsgBuf);

}

 

// Routine Description: Placeholder to demo when async I/O

// might want to do other processing.

void GoDoSomethingElse(void)

{

    wprintf(L"Inside GoDoSomethingElse()...\n");

}

 

// Routine Description:

//      Demonstrate async ReadFile() operations that can catch

//      End-of-file conditions. Unless the operation completes

//      synchronously or the file size happens to be an exact

//      multiple of BUF_SIZE, this routine will eventually force

//      an EOF condition on any file.

 

// Parameters:

//      hEvent - pre-made manual-reset event.

//      hFile - pre-opened file handle, overlapped.

//      inBuffer - the buffer to read in the data to.

//      nBytesToRead - how much to read (usually the buffer size).

// Return Value: Number of bytes read.

DWORD AsyncTestForEnd(HANDLE hEvent, HANDLE hFile)

{

    WCHAR inBuffer[BUF_SIZE];

    DWORD nBytesToRead      = BUF_SIZE;

    DWORD dwBytesRead       = 0;

    DWORD dwFileSize        = GetFileSize(hFile, NULL);

    OVERLAPPED stOverlapped = {0};

    DWORD dwError  = 0;

    LPCTSTR errMsg = NULL;

    BOOL bResult   = FALSE;

    BOOL bContinue = TRUE;

 

    // Set up overlapped structure event. Other members are already initialized to zero.

    stOverlapped.hEvent = hEvent;

 

    // This is an intentionally brute-force loop to force the EOF trigger.

    // A properly designed loop for this simple file read would use the

    // GetFileSize() API to regulate execution. However, the purpose here

    // is to demonstrate how to trigger the EOF error and handle it.

    while(bContinue)

    {

        // Default to ending the loop.

        bContinue = FALSE;

       

        // Attempt an asynchronous read operation.

        wprintf(L"Asynchronous read attempt...\n");

        bResult = ReadFile(hFile,inBuffer,nBytesToRead,&dwBytesRead,&stOverlapped);

    

        dwError = GetLastError();

 

        // Check for a problem or pending operation.

        if (!bResult)

        {

            // If the function fails, or is completing asynchronously

            // the return value is zero (FALSE)

            wprintf(L"ReadFile() returns %u. Failed or asynchronous completion...\n", bResult);

            switch (dwError)

            {

                  case ERROR_HANDLE_EOF:

                    {

                    // Another check

                    wprintf(L"\nReadFile() returned FALSE and EOF condition, async EOF not triggered.\n");

                    break;

                }

                case ERROR_IO_PENDING:

                {

                    BOOL bPending=TRUE;

 

                    // Loop until the I/O is complete, that is: the overlapped event is signaled.

                    while(bPending)

                    {

                        bPending = FALSE;

                       

                        // Pending asynchronous I/O, do something else

                        // and re-check overlapped structure.

                        wprintf(L"\nReadFile() operation is pending...\n");

    

                        // Do something else then come back to check.

                        GoDoSomethingElse();

    

                        // Check the result of the asynchronous read

                        // without waiting (forth parameter FALSE).

                        bResult = GetOverlappedResult(hFile,&stOverlapped,&dwBytesRead,FALSE) ;

    

                        if (!bResult)

                        {

                            switch (dwError = GetLastError())

                            {

                                case ERROR_HANDLE_EOF:

                                {

                                    // Handle an end of file

                                    wprintf(L"GetOverlappedResult() found EOF\n");

                                    break;

                                }

 

                                case ERROR_IO_INCOMPLETE:

                                {

                                    // Operation is still pending, allow while loop

                                    // to loop again after printing a little progress.

                                    wprintf(L"GetOverlappedResult() I/O Incomplete\n");

                                    bPending = TRUE;

                                    bContinue = TRUE;

                                    break;

                                }

 

                                default:

                                {

                                    // Decode any other errors codes.

                                    errMsg = ErrorMessage(dwError);

                                    wprintf(L"GetOverlappedResult() failed, error %d: %s\n", dwError, errMsg);

                                    LocalFree((LPVOID)errMsg);

                                }

                            }

                        }

                        else

                        {

                                          wprintf(L"GetOverlappedResult() is pretty fine!\n");

                            wprintf(L"ReadFile() operation completed\n");

 

                            // Manual-reset event should be reset since it is now signaled.

                            if(ResetEvent(stOverlapped.hEvent) != 0)

                                                wprintf(L"ResetEvent() is OK!\n");

                                          else

                                                wprintf(L"ResetEvent() failed! Error %u\n", GetLastError());

                        }

                    }

                    break;

                }

 

                default:

                {

                    // Decode any other errors codes.

                    errMsg = ErrorMessage(dwError);

                    wprintf(L"ReadFile() GetLastError() unhandled, error %d: %s\n", dwError, errMsg);

                    LocalFree((LPVOID)errMsg);

                    break;

                }

            }

        }

        else

        {

            // EOF demo did not trigger for the given file.

            // Note that system caching may cause this condition on most files

            // after the first read. CreateFile() can be called using the

            // FILE_FLAG_NOBUFFERING parameter but it would require reads are

            // always aligned to the volume's sector boundary. This is beyond

            // the scope of this example. See comments in the main() function.

            wprintf(L"ReadFile() returns %u, completed synchronously\n", bResult);

        }

 

        // The following operation assumes the file is not extremely large, otherwise

        // logic would need to be included to adequately account for very large

        // files and manipulate the OffsetHigh member of the OVERLAPPED structure.

        stOverlapped.Offset += dwBytesRead;

        if (stOverlapped.Offset < dwFileSize)            

            bContinue = TRUE;

    }

 

    return stOverlapped.Offset;

}

 

// To force an EOF condition, execute this application specifying a

// zero-length file. This is because the offset (file pointer) must be

// at or beyond the end-of-file marker when ReadFile() is called.

int wmain(int argc, WCHAR *argv[])

{

    HANDLE hEvent;

    HANDLE hFile;

    DWORD dwReturnValue;

      DWORD dwError;

      LPCTSTR errMsg;

 

    if( argc != 2 )

    {

        wprintf(L"No arguments supplied!\n");

        wprintf(L"Usage: %s <file_name_to_be_read>\n", argv[0]);

        wprintf(L"Example: %s C:\\mytestfile.txt\n", argv[0]);

        wprintf(L"         The file must exist\n");

        return 1;

    }

 

    hFile = CreateFile(argv[1],                // file to open

                       GENERIC_READ,           // open for reading

                       FILE_SHARE_READ,        // share for reading

                       NULL,                   // default security

                       OPEN_EXISTING,          // existing file only

                       FILE_FLAG_OVERLAPPED,   // overlapped operation

                       NULL);                  // no attr. template

 

    if (hFile == INVALID_HANDLE_VALUE)

    {

        dwError = GetLastError();

        errMsg = ErrorMessage(dwError);

        wprintf(L"Could not open file, error %d: %s\n", dwError, errMsg);

        LocalFree((LPVOID)errMsg);

        return 1;

    }

      else

            wprintf(L"CreateFile() is pretty fine!\n");

 

    hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

 

    if (hEvent == NULL)

    {

        dwError = GetLastError();

        errMsg = ErrorMessage(dwError);

        wprintf(L"Could not create event: %d %s\n", dwError, errMsg);

        LocalFree((LPVOID)errMsg);

        return 1;

    }

      else

            wprintf(L"CreateEvent() is  working!\n");

 

    dwReturnValue = AsyncTestForEnd(hEvent, hFile);

    wprintf(L"Read complete. Bytes read: %d\n", dwReturnValue);

 

    if(CloseHandle(hFile) != 0)

            wprintf(L"hFile handle was closed!\n");

      else

            wprintf(L"Failed to close hFile handle!\n");

 

    if(CloseHandle(hEvent) != 0)

            wprintf(L"hEvent handle was closed!\n");

      else

            wprintf(L"Failed to close hEvent handle!\n");

 

      return 0;

}

 

To test this program, firstly, create an empty text file on C drive. In this case the file name used is mytesttextfile.txt.

 

Testing for the End of a File Program Example: Creting a text file for testing

 

Build and run the project with the empty file name as the argument. The following Figure shows the sample output.

 

Testing for the End of a File Program Example: A sample console program output in action 1

 

Then, put some text in the text file and save it. Re-run the project. The following screenshot shows the sample output.

 

Testing for the End of a File Program Example: A sample console program output in action 2

 

 

 

 

< Windows Files 24 | Win32 Programming | Win32 File Index | Windows Files 26 >