Windows System Programming: File I/O Operations
Tags: windows, systemprogramming, cpp
Published: 2020-08-18 15:26:31

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**](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/)

To write into a file, you need to first create a file. And this can be done by [`CreateFileA`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea) function.

```c++
HANDLE CreateFileA(
  LPCSTR                lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);
```
Functions parameters description as follows
+ **lpFileName** &rarr; The name of the file or device to be created or opened
+ **dwDesiredAccess** &rarr; 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](https://docs.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights) | [FILE ACCESS AND SECURITY RIGHTS](https://docs.microsoft.com/en-us/windows/win32/fileio/file-security-and-access-rights) | [FILE ACCESS RIGHTS CONSTANTS](https://docs.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants)
+ **dwShareMode** &rarr; The requested sharing mode of the file or device. Use `0x0`, if you don't want to share this file.
+ **lpSecurityAttributes** &rarr; A pointer to a [SECURITY_ATTRIBUTES](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560\(v=vs.85\)) structure. This parameter can be `NULL`
+ **dwCreationDisposition** &rarr; 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** &rarr; 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** &rarr; 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`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile)
```c++
BOOL WriteFile(
  HANDLE       hFile,
  LPCVOID      lpBuffer,
  DWORD        nNumberOfBytesToWrite,
  LPDWORD      lpNumberOfBytesWritten,
  LPOVERLAPPED lpOverlapped
);
```
Function parameters as follows
+ **hFile** &rarr; A handle to the file or I/O device with the write access. 
+ **lpBuffer** &rarr; A pointer to the buffer containing the data to be written to the file or device.
+ **nNumberOfBytesToWrite** &rarr; The number of bytes to be written to the file or device. 
+ **lpNumberOfBytesWritten** &rarr; 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** &rarr; A pointer to an [OVERLAPPED](https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-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`](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile) function.
```c++
BOOL ReadFile(
  HANDLE       hFile,
  LPVOID       lpBuffer,
  DWORD        nNumberOfBytesToRead,
  LPDWORD      lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
);
```
Function parameters description as follows
+ **hFile** &rarr; A handle to the file or I/O device with the read access. 
+ **lpBuffer** &rarr; A pointer to the buffer that receives the data read from a file or device.
+ **nNumberOfBytesToRead** &rarr; The maximum number of bytes to be read.
+ **lpNumberOfBytesRead** &rarr; 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** &rarr; A pointer to an [OVERLAPPED](https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-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
```c++
#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;
}
```

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

+ Email: tbhaxor@gmail.com
+ Twitter: [@tbhaxor](https://twitter.com/tbhaxor)
+ Facebook: [@tbhaxor](https://fb.com/tbhaxor)
+ GitHub: [@tbhaxor](https://github.com/tbhaxor)
+ LinkedIn: [@gurkirat--singh](https://www.linkedin.com/in/gurkirat--singh)
+ Instagram: [@_tbhaxor_](https://instagram.com/_tbhaxor_)