Your hobby sounds cool. I always try to write the most portable code possible too. In fact, a class file I think Ben might find helpful is one I developed for a bank record project I was working on. It was my first attempt to use streams, but I'm pretty happy with the results.
The following code keeps track of files full of a type of object (determined by the arguement passed to a template). You can add, retrieve, delete, and modify objects in the file. Erase the contents of the file, copy the file, and do a few other things and it's all made using ANSI standard code.
There are certainly some things that can be added (like an insert object function, which would be easily implemented), and I suspect there are better or more efficient ways to do implement the code, but I swear, as it is, the code makes it soooo easy to maintain files of objects. I tried to clean it up a little for display in the narrow forum text area, but it's still not as clear as it is in my .h file:
//file handler template header
//handles creation of, management of, copying of,
//and printing of files of
//a group of similar objects.
//Note: print funciton reliant on overloaded << operator
#ifndef FILEHANDLER_H
#define FILEHANDLER_H
#include<iostream>
using std::ios;
using std::cerr;
using std::endl;
#include <fstream>
using std::fstream;
using std::ifstream;
using std:

fstream;
template< class T >
class FileHandler
{
public:
//constructor takes 3 arguements: the filename, an array of objects,
//and the size of the array, it writes the object contained
//in the array to the file
FileHandler( const char *, const T[], const int );
//takes filename arguement, counts the objects in file
FileHandler( const char * );
//erase the contents of a file
clearFile();
//overwrite entire file truncating its former contents
overwriteFile( const T [], const int );
//overwrite single record
replaceObject( T , const unsigned );
//append an object to the end of the list
addObject( const T& );
//delete a single object
deleteObject( const unsigned );
//delete a range of objects
deleteObjects( const unsigned, const unsigned );
//returns # of objects in file
const int getObjCount() { return objectCount; }
//copy member file to different file
copyFile( const char * );
//returns a copy of an object positioned at a given index
const T returnObject( const int );
//output contents of member file
printFile();
//output single object of member file
printRecord( const int );
private:
const char * fileName;
int objectCount;
fstream inOutObject;
writeToPosition( T , const unsigned );
handleError( const int ); //int error type
};
//member function definitions
template< class T >
FileHandler< T >::FileHandler( const char *nameOfFile,
const T array[], const int objCnt ):
inOutObject( nameOfFile,
ios::in | ios:

ut | ios::binary | ios::ate ),
fileName( nameOfFile )
{
objectCount = objCnt;
if( !inOutObject )
{
handleError( 0 );
exit( 1 );
}
overwriteFile( array, objCnt );
}
template< class T >
FileHandler< T >::FileHandler( const char *nameOfFile ):
inOutObject( nameOfFile,
ios::in | ios:

ut | ios::binary | ios::ate ),
fileName( nameOfFile )
{
objectCount = 0;
T objectVar;
if( !inOutObject )
{
handleError( 0 );
exit( 1 );
}
inOutObject.seekg(0);
inOutObject.read( reinterpret_cast<char *>( &objectVar ), sizeof( T ));
while( !inOutObject.eof() )
{
++objectCount;
inOutObject.read( reinterpret_cast<char *>( &objectVar ), sizeof( T ));
}
inOutObject.clear();
}
template< class T >
FileHandler< T >::clearFile()
{
ofstream eraser( fileName, ios:

ut | ios::binary | ios::trunc );
objectCount = 0;
}
template< class T >
FileHandler< T >:

verwriteFile( const T arrayOfObjects[], const int numberOfElements )
{
clearFile();
objectCount = numberOfElements;
try
{
for ( int i = 0; i < objectCount; i++ )
{
writeToPosition( arrayOfObjects
, i );
}
}
catch( ... )
{
handleError( 2 );
}
inOutObject.flush();
}
template< class T >
FileHandler< T >::replaceObject( T insObj, const unsigned position )
{
if ( position < objectCount )
{
writeToPosition( insObj, position );
}
else
handleError( 3 );
}
template< class T >
FileHandler< T >::deleteObject( const unsigned index )
{
if( index < objectCount )
{
int i;
T *storage = new T[objectCount];
//storage array is loaded with all the elements than aren't deleted,
//then the member file is overwritten according to storage's info
for ( i = 0; i < index; i++ )
storage = returnObject( i );
for ( i = index; i < objectCount; i++ )
storage = returnObject( i + 1 );
overwriteFile( storage, --objectCount );
delete [] storage;
}
else
handleError( 3 );
}
template< class T >
FileHandler< T >::deleteObjects( const unsigned begIndex, const unsigned endIndex )
{
if ( begIndex >= 0 && endIndex < objectCount )
{
int difference = endIndex - begIndex,
i;
//storage array is loaded with all the elements than aren't deleted,
//then the member file is overwritten according to storage's info
T *storage = new T[ objectCount - ( difference + 1 ) ];
//load storage array
for( i = 0; i < begIndex; i++ )
storage = returnObject( i );
for( i = endIndex + 1; i < objectCount; i++ )
//place objects after endIndex into the proper space in the array
storage[i - ( difference + 1 )] = returnObject( i );
objectCount -= difference + 1;
overwriteFile( storage, objectCount );
delete [] storage;
}
else
handleError( 3 );
}
template< class T >
FileHandler< T >::addObject( const T &obToAdd )
{
writeToPosition( obToAdd, objectCount++ );
}
template< class T >
FileHandler< T >::copyFile( const char *copiedFileName )
{
ofstream outPrintFileCopy( copiedFileName, ios:
ut | ios::trunc );
if ( !outPrintFileCopy )
{
handleError( 1 );
exit( 1 );
}
T copyObject;
inOutObject.seekg( 0 );
inOutObject.read( reinterpret_cast<char *>( ©Object ), sizeof( T ));
while( !inOutObject.eof() )
{
outPrintFileCopy.write( reinterpret_cast< char * >( ©Object ), sizeof( T ));
inOutObject.read( reinterpret_cast<char *>( ©Object ), sizeof( T ));
}
inOutObject.clear();
cout << "Copied file to: " << copiedFileName << endl;
}
template< class T >
const T FileHandler< T >::returnObject( const int index )
{
T objectVar;
if ( index < objectCount )
{
inOutObject.seekg( index * sizeof( T ));
inOutObject.read( reinterpret_cast<char *>( &objectVar ), sizeof( T ));
}
else
{
handleError( 3 );
}
return objectVar;
}
//print function reliant on overloaded << operator
template< class T >
FileHandler< T >:
rintFile()
{
int i = 0; //used to indentify record index
while( i < objectCount )
{
printRecord( i++ );
}
}
template< class T >
FileHandler< T >:
rintRecord( const int index )
{
if ( index < objectCount )
cout << /*"Record " << index << '\n' <<*/ returnObject( index ) << '\n' << endl;
else
handleError( 3 );
}
//private functions
template< class T >
FileHandler< T >::writeToPosition( T insObj, const unsigned position )
{
inOutObject.seekp( ( sizeof T ) * position );
inOutObject.write( reinterpret_cast<char *>( &insObj ), sizeof( T ));
inOutObject.flush();
}
template< class T >
FileHandler< T >::handleError( const int errorType )
{
switch( errorType )
{
case 0:
cerr << "File \"" << fileName << "\" does not exist. Aborting..." << endl;
break;
case 1:
cerr << "File could not be opened" << endl;
break;
case 2:
cerr << "Error creating new file" << endl;
break;
case 3:
cerr << "Passed subscript out of bounds" << endl;
break;
default:
cerr << "Error of unknown type" << endl;
}
}
#endif
..........................................................
If someone can use the source, I can just send the file to make things easier.
I was sorta also hoping people can give some ideas on how to improve the code. I have a few ideas of my own, but I'd like to hear from others. ![[nosmiley] [nosmiley] [nosmiley]](/data/assets/smilies/nosmiley.gif)