# [C++] File Handler Class

8 replies to this topic

### #1CoryG89

New Member

• Members
• 3 posts

Posted 27 July 2010 - 04:41 AM

I am trying to design a class that will handle all of my general file operations for the application I am working on currently, as well as any I might do in the future in C++. The class is built so that I have a public fstream object as a member. The class seems to be working fine, all except for that it will not seem to read the data from the file when I go through the object and use the file stream as a public member. I am doing everything exactly the same as I would normally so I don't understand why this is happening.

I remember reading somewhere that when you pass a file stream to a function, you must do it by reference. For what reason is this? Perhaps it has something to do with why I cannot get my stream to read data from my file when it is part of an object? Anyone have any ideas?

### #2Wernaeh

Senior Member

• Members
• 368 posts

Posted 27 July 2010 - 08:13 AM

Suggestions for the error reason are hard to give without any code excerpt. Double check your file names, check the stream error states after each operation, ...

The following

class MyFile

{

public: std::ifstream myStream;

};

MyFile file;

file.myStream.open("SomeFile.txt");

char buffer[512];

file.myStream.getline(buffer, 512);

file.myStream.close();


should work as expected.

Concerning the reference issues, you shouldn't actually be able to pass a file stream around by value (there is no copy constructor), so pass-by-reference and pass-by-pointer are the only available options...

Apart from that - why do you write a wrapper around fstream ? The only reason I'd see for something like this is the ability to switch implementation to compressed resource files or network files on the fly. Then, however, the boost IO Iosteams libraries (boost::iostreams::device, ...) provide a better access to the entire concept than the STL.

Cheers,
- Wernaeh
Some call me mathematician, some just call me computer guy. Yet, I prefer the term professional weirdo :)

### #3CoryG89

New Member

• Members
• 3 posts

Posted 28 July 2010 - 10:00 PM

Wernaeh said:

Apart from that - why do you write a wrapper around fstream?

Well, it was mostly for practice implementing classes and exception handling. I am currently working on a program for class that can be used to run a book store. So really the only thing the class is acting as is a wrapper, with extended exception handling and a few useful functions I plan on writing that specifically work on data files. For instance I have a function that counts the number of lines in a data file, another that will count the number of datum on each line using the number of delimiters. The class is also responsible for storing the delimiter used, also a bool flag stating whether a file is currently open or not.


#include <cstring>

#include <cstdlib>

#include <fstream>

#include <string>

#include <cctype>

using namespace std;

enum FileModes { APPEND, INSERT, INPUT, OUTPUT, TRUNCATE };

//////// NODE COMPOSITION - self referential data structure

class FileHandler

{

private:

char filename[51];				// filename with a maximum of 50 characters

int fileMode;					// determines how the data file is opened for use is the stream

public:

fstream stream;					// C++ stream capable of reading, writing, or both simultaneously

bool status;					// true if the file is in use

char delimiter;					// stores the delimiter used

// Exception classes

class DoesNotExist { };

class NoFileName { };

class CannotOpen { };

//////// CONSTRUCTOR / DESCTRUCTOR

FileHandler(char *newFile)

{

strcpy_s(filename, newFile);	// set the filename for our filehandler

status = false;					// file has not been opened yet

}

~FileHandler()

{

}

//////// METHODS

// stores a new delimiter for the stream

void setDelimiter(char newDel)

{

delimiter = newDel;

}

// returns the number of lines in the stream

int CountLines(bool countBlanks = false)

{

int count = 0;

string buffer;

while(getline(stream,buffer))

{

if(buffer != "")		// only count if line isn't blank

count++;

else if(countBlanks == true)	// line is blank, only count if true

count++;

}

return count;

}

// returns number of individual datum on the first line; others are assumed to be the same

int CountCells()

{

int numOfCells = 0;

char buffer = ' ';

int testCount = 0;

while(buffer != '\n')

{

stream.get(buffer);		// read a single character into the buffer

if(buffer == delimiter)

numOfCells++;

cout << "Contents of Buffer: " << buffer << endl;

cout << "Number of Cells: " << numOfCells << endl;

system("pause");

}

numOfCells++;

cout << "Final number of cells: " << numOfCells << endl;

system("pause");

return numOfCells;

}

// Verifies that there is a stored filename in the FileNode, if not it obtains one

void verifyFilename()

{

try

{

if(!filename)

throw NoFileName();

}

catch(NoFileName)

{

cout << "There is no valid filename loaded." << endl;

cout << "Please enter the filename of the desired stream: ";

cin >> *filename;

}

}

// Opens a file for both input and output

void openFile()

{

try

{

stream.open(filename, ios::in | ios::out | ios::app);

if(stream.fail())

throw CannotOpen();

else

status = true;	// set flag open

}

catch(CannotOpen())

{

cout << "ERROR: The file cannot be opened." << endl;

system("pause");

}

}

// Opens a file using a specified mode, see global enum for specifics on the modes

void OpenFile(int mode)

{

verifyFilename();

switch(mode)

{

case 0:		// "APPEND" contents preserved | all output at end of file

try

{

stream.open(filename, ios::out | ios::app);

if(stream.fail())

throw CannotOpen();

else

status = true;	// set flag open

}

catch(CannotOpen())

{

cout << "ERROR: The file cannot be opened." << endl;

system("pause");

}

break;

case 1:		// "INSERT" contents preserved | output written anywhere

try

{

stream.open(filename, ios::out | ios::ate);

if(stream.fail())

throw DoesNotExist();

else

status = true;	// set flag open

}

catch(CannotOpen())

{

cout << "ERROR: The file cannot be opened." << endl;

system("pause");

}

break;

case 2:		// "INPUT" if file does not exist, it will not be created

try

{

cout << "Open Mode: INPUT" << endl;

system("pause");

stream.open(filename, ios::in);

if(stream.fail())

throw DoesNotExist();

else

status = true;	// set flag open

}

catch(DoesNotExist)

{

cout << "ERROR: The file does not exist." << endl;

system("pause");

}

break;

case 3:		// "OUTPUT" the file's contents will be deleted if it exists

try

{

stream.open(filename, ios::in);

if(stream.fail())

throw CannotOpen();

else

status = true;	// set flag open

}

catch(CannotOpen)

{

cout << "ERROR: The file cannot be opened." << endl;

system("pause");

}

break;

case 4:		// "TRUNCATE" opened for input & output, contents deleted

try

{

stream.open(filename, ios::in | ios::out | ios::trunc);

if(stream.fail())

throw CannotOpen();

else

status = true;	// set flag open

}

catch(CannotOpen)

{

cout << "ERROR: The file cannot be opened." << endl;

system("pause");

}

break;

}

}

// This is mostly a wrapper function, will simply call the filestream's close() function, but will

// also set our status flag to back to false

void CloseFile()

{

stream.close();

status = false;

}

};

So, here's the thing. I am not actually getting any errors, the program run's fine it is just that no data actually get's read, all the variables that I read data into are empty. As you can see the opening and closing of the data file is handled in the object itself. But when I go to read data from the file I do it like the implementation you show.

FileHandler BookFile;

BookFile.OpenFile(INPUT);

BookFile.stream.getline(.....

I do it like this and the variables I read into end up holding nothing. But if I open up a seperate stream outside my object and read them into the same variables the exact same way but with a different file stream it works perfectly. Kind of baffling...

### #4fireside

Senior Member

• Members
• 1615 posts

Posted 29 July 2010 - 05:58 AM

Not being a c++ guru or anything, but when you instantiate it's normally:

FileHandler bookfile = new Filehandler(name of file);

or is that java? I think they're the same. Anyway, you have the file name in the constructor but you haven't passed it in your code you gave for an example unless that was an abbreviated code or something. I don't know about passing a stream by reference, but you're not doing that. You're just passing the filename and the class is opening the stream and using it, so it's essentially the same thing you would be doing otherwise.
Currently using Blender and Unity.

### #5CoryG89

New Member

• Members
• 3 posts

Posted 29 July 2010 - 05:49 PM

fireside said:

Not being a c++ guru or anything, but when you instantiate it's normally:

FileHandler bookfile = new Filehandler(name of file);

I don't know about passing a stream by reference, but you're not doing that. You're just passing the filename and the class is opening the stream and using it, so it's essentially the same thing you would be doing otherwise.

Yeah that is how I have it instantiated. I just typed that up to fast right there. My bad. And yeah, I'm not passing a file stream by reference, the file stream is created when the object is instantiated and I access it through the dot operator. This just doesn't seem to be working, and I remember reading that a file stream has to be passed by reference or pointer. I was just wondering if this may have anything to do with why it isn't working. I guess not though.

### #6.oisyn

DevMaster Staff

• Moderators
• 1842 posts

Posted 29 July 2010 - 10:18 PM

fireside said:

Not being a c++ guru or anything, but when you instantiate it's normally:

FileHandler bookfile = new Filehandler(name of file);

or is that java?
Yes

Quote

I think they're the same.
No. In C++, everything is a value type. If you want to have a reference rather than a value, you should use T* or T&. The new operator yields a pointer to the created object (T*). A definition like FileHandler bookfile; implicetly constructs bookfile.
-
Currently working on: the 3D engine for Tomb Raider.

### #7fireside

Senior Member

• Members
• 1615 posts

Posted 29 July 2010 - 10:38 PM

Thanks oisyn. I'd better brush up on my c++ by writing a few programs in it again. Apparently it should have been FileHandler bookfile(filename);
Currently using Blender and Unity.

### #8poita

Senior Member

• Members
• 322 posts

Posted 31 July 2010 - 02:09 PM

fireside said:

Thanks oisyn. I'd better brush up on my c++ by writing a few programs in it again. Apparently it should have been FileHandler bookfile(filename);

They're both right, they're just used in different situations. In general, not using new is the preferred way, and you should only use new when you need to.

### #9fireside

Senior Member

• Members
• 1615 posts

Posted 31 July 2010 - 04:42 PM

I think my syntax was off, though. If it would have been for a pointer, I should have written

Filehandler *bookfile = new Filehandler(filename);

I've been in Java and As3 a lot lately, but I get you're point. I think most people using C++ use pointers because they want a reference with a class. Anyway, my point was that the code shown wasn't passing the filename to the constructor. I had actually forgotten about the other way because I hardly ever see anyone use it with a class so it looked weird and it doesn't even exist in Java, I don't think. There would be too much overhead with it. I think some people declare like that and then pass by reference, but it's not many.
Currently using Blender and Unity.

#### 1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users