DEV Community

loading...

Windows System Programming: File I/O Operations

Gurkirat Singh
Yet another noob script kiddie and non TPP registered failure :)
・5 min read

Hello There!

First of all, I am really sorry for taking a long time in writing this post. I have no reason / excuse to make for it.

What is not cool about programming is to not to learn how to deal with file operations. File operation are very handy when you have to read / write large data. You will first learn about writing into the file and then how to read from it.

The header file that will be used in Creating, Writing to File and Reading from File is fileapi.h

To write into a file, you need to first create a file. And this can be done by CreateFileA function.

HANDLE CreateFileA(
  LPCSTR                lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);
Enter fullscreen mode Exit fullscreen mode

Functions parameters description as follows

  • lpFileName → The name of the file or device to be created or opened
  • dwDesiredAccess → The requested access to the file or device. The most commonly used values are GENERIC_READ, GENERIC_WRITE, or both (GENERIC_READ | GENERIC_WRITE). You can see the list of different types of access from here: GENERIC ACCESS RIGHTS | FILE ACCESS AND SECURITY RIGHTS | FILE ACCESS RIGHTS CONSTANTS
  • dwShareMode → The requested sharing mode of the file or device. Use 0x0, if you don't want to share this file.
  • lpSecurityAttributes → A pointer to a SECURITY_ATTRIBUTES structure. This parameter can be NULL
  • dwCreationDisposition → An action to take on a file or device that exists or does not exist. For devices other than files, this parameter is usually set to OPEN_EXISTING. The possible values can be ( CREATE_ALWAYS, CREATE_NEW, OPEN_ALWAYS, OPEN_EXISTING, TRUNCATE_EXISTING )
  • dwFlagsAndAttributes → The file or device attributes and flags, FILE_ATTRIBUTE_NORMAL being the most common default value for files. This parameter can also contain combinations of flags (FILE_FLAG_*)
  • hTemplateFile → A valid handle to a template file with the GENERIC_READ access right. This parameter can be NULL

NOTE: If the function succeeds, the return value is an open handle to the specified file, device, named pipe, or mail slot

You have created the file, now writing to it can be done by WriteFile

BOOL WriteFile(
  HANDLE       hFile,
  LPCVOID      lpBuffer,
  DWORD        nNumberOfBytesToWrite,
  LPDWORD      lpNumberOfBytesWritten,
  LPOVERLAPPED lpOverlapped
);
Enter fullscreen mode Exit fullscreen mode

Function parameters as follows

  • hFile → A handle to the file or I/O device with the write access.
  • lpBuffer → A pointer to the buffer containing the data to be written to the file or device.
  • nNumberOfBytesToWrite → The number of bytes to be written to the file or device.
  • lpNumberOfBytesWritten → A pointer to the variable that receives the number of bytes written when using a synchronous hFile parameter. This parameter can be NULL only when the lpOverlapped parameter is not NULL.
  • lpOverlapped → A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise this parameter can be NULL.

If the function succeeds, the return value is nonzero (TRUE).

After the data has been written, you should close the handle to flush all the data stored in the buffer into file.

Now comes, reading the file contents. You need to use ReadFile function.

BOOL ReadFile(
  HANDLE       hFile,
  LPVOID       lpBuffer,
  DWORD        nNumberOfBytesToRead,
  LPDWORD      lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
);
Enter fullscreen mode Exit fullscreen mode

Function parameters description as follows

  • hFile → A handle to the file or I/O device with the read access.
  • lpBuffer → A pointer to the buffer that receives the data read from a file or device.
  • nNumberOfBytesToRead → The maximum number of bytes to be read.
  • lpNumberOfBytesRead → A pointer to the variable that receives the number of bytes read. This parameter can be NULL only when the lpOverlapped parameter is not NULL.
  • lpOverlapped → A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise this parameter can be NULL.

If the function succeeds, the return value is nonzero (TRUE).

The complete code as follows

#include <Windows.h>
#include <iostream>
#include <fileapi.h>
#include <string>

int main(int argc, char** argv)
{
    if (argc == 1) {
        printf("usage: %s <filename>", argv[0]);
        return 1;
    }

    /*
     * Function Documentation
     * https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
     */
    HANDLE hFile = CreateFileA(argv[1], 
        GENERIC_WRITE, 
        FILE_SHARE_READ, 
        NULL, 
        CREATE_NEW, 
        FILE_ATTRIBUTE_NORMAL, 
        NULL);

    if (hFile == INVALID_HANDLE_VALUE) {
        switch (GetLastError())
        {
        case ERROR_FILE_EXISTS:
            printf("File '%s' exists\n", argv[1]);
            break;
        default:
            printf("Error: %ul", GetLastError());
            break;
        }
        return 1;
    } else {
        printf("File Created\n");
    }

    // WRITING TO FILE
    std::string strBuff = "Hello World!! This is the file containing some random thought";
    DWORD bytesToWrite = strBuff.size(), bytesWritten;

    // wrtiting buffer to file
    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile
    BOOL bWrite = WriteFile(hFile, strBuff.c_str(), bytesToWrite, &bytesWritten, NULL);

    if (bWrite) {
        printf("Buffer written to file\n");
    } else if (bytesToWrite != bytesWritten) {
        printf("Bytes written != bytes to write");
        printf("\nSuccessfully wrote %d bytes to %s", bytesWritten, argv[1]);
        CloseHandle(hFile);
        return 1;
    } else {
        switch (GetLastError())
        {
        default:
            printf("Error: WRITEFILE: %d\n", GetLastError());
            CloseHandle(hFile); // closing file handle
            return 1;
        }
    }
    CloseHandle(hFile); // closing file handle

    // opening file handle to read the file
    hFile = CreateFileA(argv[1], 
        GENERIC_READ, 
        FILE_SHARE_READ, 
        NULL, 
        OPEN_EXISTING,  // at this time the file already exists 
        FILE_ATTRIBUTE_NORMAL, 
        NULL);

    DWORD nToRead = 15; // let's read 15 byts
    char chBuff[16];
    DWORD nRead;

    // reading file
    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
    BOOL bRead = ReadFile(hFile, &chBuff, nToRead, &nRead, NULL);
    chBuff[15] = '\0'; // terminating string

    if (bRead) {
        printf("DATA: %s\n", chBuff);
    }
    else if (nToRead != nRead) {
        printf("Number of bytes to read != number of bytes read\n");
    } else {
        switch (GetLastError())
        {
        case ERROR_NOACCESS:
            printf("ERROR: No access to read file '%s'\n", argv[1]);
            break;
        default:
            printf("Error: READFILE: %d\n", GetLastError());
        }
        CloseHandle(hFile); // closing file handle
        return 1;
    }

    CloseHandle(hFile); // closing file handle

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

I hope you have enjoyed this post. Follow the links to reach me

Discussion (0)