File I/O in Visual C++
by Ernest "TANSTAAFL" Pazera

I've seen a lot of questions asked on this topic lately, so I felt I'd write a little thingie to show y'all how to do it. It's really very simple.

In this article, I'm only actually covering the essentials. In Game Programming, most File I/O features are unnecessary. Most often, you will want to do one of three things:

  1. Open an existing file for loading in information
  2. Open a new file for saving information, or overwriting an existing file

These two things will get you pretty far.

Some prototypes you will want to be familiar with (these are straight out of the VC++ help file):

HANDLE CreateFile(
    LPCTSTR  lpFileName,            // pointer to name of the file 
    DWORD  dwDesiredAccess,         // access (read-write) mode 
    DWORD  dwShareMode,             // share mode 
    LPSECURITY_ATTRIBUTES  lpSecurityAttributes,  // pointer to security descriptor 
    DWORD  dwCreationDistribution,  // how to create 
    DWORD  dwFlagsAndAttributes,    // file attributes 
    HANDLE  hTemplateFile           // handle to file with attributes to copy  
   );

BOOL CloseHandle(
    HANDLE  hObject     // handle to object to close  
   );

BOOL ReadFile(
    HANDLE  hFile,                 // handle of file to read 
    LPVOID  lpBuffer,              // address of buffer that receives data  
    DWORD  nNumberOfBytesToRead,   // number of bytes to read 
    LPDWORD  lpNumberOfBytesRead,  // address of number of bytes read 
    LPOVERLAPPED  lpOverlapped     // address of structure for data 
   );

BOOL WriteFile(
    HANDLE  hFile,                   // handle to file to write to
    LPCVOID  lpBuffer,               // pointer to data to write to file
    DWORD  nNumberOfBytesToWrite,    // number of bytes to write
    LPDWORD  lpNumberOfBytesWritten, // pointer to number of bytes written
    LPOVERLAPPED  lpOverlapped       // addr. of struct needed for overlapped I/O
   );

Some variables you will need for reading files:

//file handle
HANDLE hFile;
//something to contain the number of bytes read
DWORD dwNumRead;
//a boolean test variable, to test for success of reads
BOOL bTest;
//a buffer… can actually be of any type
DWORD dwBuffer[256];

Opening an existing file for reading:

hFile = CreateFile("D:\\mypath\\myfile.dat", GENERIC_READ, FILE_SHARE_READ,
                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
/* if there is a problem opening the file, a call to
 GetLastError will tell you what it is */

To read from the file:

bTest= ReadFile(hFile, dwBuffer, sizeof(DWORD)*256, &dwNumRead,NULL);
/* bTest will be TRUE if the read is successful.
 If false, take a look at GetLastError */

To close the file:

BTest=CloseHandle(hFile);
/*bTest will be true if the file closed correctly. 
 If false, take a look at GetLastError */

Some variables you will need for writing files:

//file handle
HANDLE hFile;
//something to contain the number of bytes read
DWORD dwNumWritten;
//a boolean test variable, to test for success of reads
BOOL bTest;
//a buffer… can actually be of any type
DWORD dwBuffer[256];

Opening a new file for writing:

hFile = CreateFile("D:\\mypath\\myfile.dat", GENERIC_WRITE, FILE_SHARE_WRITE,
                   NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
/* if there is a problem opening the file, a call to
 GetLastError will tell you what it is */

To write to the file:

bTest= WriteFile(hFile, dwBuffer, sizeof(DWORD)*256, &dwNumWritten,NULL);
/* bTest will be TRUE if the read is successful.
 If false, take a look at GetLastError */

To close the file:

BTest=CloseHandle(hFile);
/*bTest will be true if the file closed correctly.
 If false, take a look at GetLastError */

Okay… that's all there is to it. However, I'm going to leave you with a couple of examples, so that you can see what is going on in various circumstances.

Top Ten List: how to save it and load it

First, you need some sort of structure to contain your Top Ten List.

struct TopTenEntry
{
    char szName[11];
    DWORD dwScore;
};

TopTenEntry tteScore[11]; //there are 11 elements so that when
// a new score is added, it can be added as the 11th element,
// and then sorted. Elements 0 through 9 will be saved, element 10 will not

Next, you'll want a function to save a top ten list

BOOL SaveTopTenList(LPCTSTR FileName, TopTenEntry *Entries)
{
    BOOL bTest=FALSE;
    DWORD dwNumWritten=0;
    HANDLE hFile=CreateFile(FileName,GENERIC_WRITE,FILE_SHARED_WRITE,
                            NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    bTest = WriteFile(hFile,Entries,sizeof(TopTenEntry)*10,&NumWritten, NULL);
    bTest= CloseHandle(hFile);
    return(TRUE);
}

You'll probably also want something to load it in…

BOOL LoadTopTenList(LPCTSTR FileName, TopTenEntry *Entries)
{
    BOOL bTest=FALSE;
    DWORD dwNumRead=0;
    HANDLE hFile=CreateFile(FileName,GENERIC_READ,FILE_SHARED_READ,
                            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    bTest = ReadFile(hFile,Entries,sizeof(TopTenEntry)*10,&NumRead, NULL);
    bTest= CloseHandle(hFile);
    return(TRUE);
}

Sorting, and other stuff I leave up to you, as it is beyond the scope of this article… maybe you'll want to extend the thing by including the date and time on the topten list, etc.

Note: I do absolutely NO error checking in my examples.

TANSTAAFL
November 4, 1998

Discuss this article in the forums


Date this article was posted to GameDev.net: 9/13/1999
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
Windows

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!