File input/output problem

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

31 Replies - 4019 Views - Last Post: 01 January 2010 - 06:33 PM Rate Topic: -----

#1 xenoslash  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 89
  • Joined: 19-August 09

File input/output problem

Posted 22 December 2009 - 07:53 AM

I am trying to make a code to test the uses of fstream functions
Here is the code

ClientData.h
#ifndef CLIENTDATA_H
#define CLIENTDATA_H

#include <string>
using namespace std;

class ClientData
{
public:
	ClientData(string="", string ="", int=0, double=0.0);

	void setAccountNumber(int);
	int getAccountNumber()const;

	void setBalance(double);
	double getBalance()const;

	void setFirstName(string);
	string getFirstName();

	void setLastName(string);
	string getLastName();

	void print();
private:
	int accountNumber;
	double balance;
	char firstName[10];
	char lastName[15];

};

#endif



ClientData.cpp
#include "ClientData.h"
#include <iostream>
using namespace std;


ClientData::ClientData(string first, string last, int number, double money)
{
	setFirstName(first);
	setLastName(last);
	setAccountNumber(number);
	setBalance(money);
}

void ClientData::setAccountNumber(int number)
{
	accountNumber=(number>0 && number<=100) ? number : 0;
}

int ClientData::getAccountNumber()const
{
	return accountNumber;
}

void ClientData::setBalance(double money)
{
	balance= (money>=0.0) ? money : 0; 
}

double ClientData::getBalance()const
{
	return balance;
}

void ClientData::setFirstName(string first)
{
	const char* firstNameValue=first.data();
	int length= (first.size()<15) ? first.size() : 14;
	strncpy (firstName, firstNameValue, 14);
	firstName[length]='\0';
}

string ClientData::getFirstName()
{
	return firstName;
}

void ClientData::setLastName(string last)
{
	const char* lastNameValue=last.data();
	int length= (last.size()<15) ? last.size() : 14;
	strncpy (lastName, lastNameValue, 14);
	lastName[length]='\0';
}

string ClientData::getLastName()
{
	return lastName;
}

void ClientData::print()
{
	cout<<"Name:"<<getFirstName()<<' '<<getLastName()<<endl;
	cout<<"Balance:"<<getBalance()<<endl;
	cout<<"Account Number:"<<getAccountNumber()<<endl;
}



BankDatabase.cpp
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "ClientData.h"
#include <string>
using namespace std;

int main()
{
ofstream outClientFile ("clients.txt",ios::out);

if (!outClientFile)
{
	cerr<<"clients.txt cannot be opened for output";
	exit(1);
}

ifstream inClientFile ("clients.txt", ios::in);

if (!inClientFile)
{
	cerr<<"clients.txt cannot be opened for input";
	exit(1);
}

int account;
char firstName[15];
char lastName[15];
double balance;

while (cin>>firstName>>lastName>>account>>balance)
{
	ClientData tempClient(firstName,lastName,account,balance);
	outClientFile.seekp((tempClient.getAccountNumber()-1)*sizeof(ClientData));
	outClientFile.write(reinterpret_cast<char*>(&tempClient) , sizeof(ClientData));
}


ClientData tempClient;

inClientFile.read(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));

while(inClientFile && !inClientFile.eof())
{
	if (tempClient.getAccountNumber()!=0)
	{
		tempClient.print();
		cout<<endl;
	}

	inClientFile.read(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));
}


return 0;
}



The problem is that let's say I type these inputs
Mary Jane 5 9.98
Erik Dee 9 88.3
End of file (ctrl Z in my computer)

In the file, the two inputs are already printed there but the numbers 5 and 9.98 are printed in other formats (hexadecimal maybe?) and there are some weird characters in each record
like this : and F
Also, I think these lines did not do what they are supposed to do

ifstream inClientFile ("clients.txt", ios::in);

//blablabla

ClientData tempClient;

inClientFile.seekg(0);
inClientFile.read(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));

while(inClientFile && !inClientFile.eof())
{
	if (tempClient.getAccountNumber()!=0)
	{
		tempClient.print();//print the client's info 
		cout<<endl;
	}

	inClientFile.read(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));
}



From the given two inputs, only 1 input is shown.
In this case, it's only Mary Jane's profile which is printed out.

If I used only 1 input then EOF, no output will be shown
If I used 3 inputs, 2 outputs only

So basically the program doesn't print the last record on the file.
Any ideas??

Is This A Good Question/Topic? 0
  • +

Replies To: File input/output problem

#2 r.stiltskin  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1833
  • View blog
  • Posts: 4,927
  • Joined: 27-December 05

Re: File input/output problem

Posted 22 December 2009 - 12:28 PM

The data for the last client entered is in the file but not being printed, but it's not because of your printing code. Your problem occurs because you have an istream and an ostream both opened on the same file simultaneously. You can solve it by closing the ostream before you open the istream.

(By the way, you should always close your files when you are finished using them.)

If you want something more versatile you can do something like this:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include "ClientData.h"
#include <string>
using namespace std;

int main()
{
// This will create the file if it doesn't already exist, but will not
//  erase it's contents if it does already exist
ofstream outFile("clients.txt",ios::out| ios::app);
outFile.close();

// This will let you read and write the file, but won't work unless
//  the file already exists. That's why I added the 2 previous lines.
// It will also let you reuse the same file on subsequent runs of the program.
fstream clientFile ("clients.txt",ios::in|ios::out|ios::binary);

if (!clientFile)
{
	cerr<<"clients.txt cannot be opened\n";
	exit(1);
}


int account;
char firstName[15];
char lastName[15];
double balance;

while (cin>>firstName>>lastName>>account>>balance)
{
	ClientData tempClient(firstName,lastName,account,balance);
	clientFile.seekp((tempClient.getAccountNumber()-1)*sizeof(ClientData));
	clientFile.write(reinterpret_cast<char*>(&tempClient) , sizeof(ClientData));
}


ClientData tempClient;


clientFile.seekp(0);

while(clientFile.read(reinterpret_cast<char*>(&tempClient),sizeof(ClientData)))
{
	if (tempClient.getAccountNumber()!=0)
	{
		tempClient.print();
		cout<<endl;
	}
}

clientFile.close();

return 0;
}




PS: when you print the file to your console, the "weird characters" occur because the numbers are not chars (single-byte data), they are ints and doubles (multi-byte data) and your shell is printing the individual bytes that make them up as if they were chars.
Was This Post Helpful? 1
  • +
  • -

#3 Huzi94  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 119
  • Joined: 14-November 09

Re: File input/output problem

Posted 22 December 2009 - 01:14 PM

Instead of
if (!clientFile)
{
	cerr<<"clients.txt cannot be opened\n";
	exit(1);
}



Use
if (clientFile.is_open())
{
	//read file
}
else
{
	cerr<<"clients.txt cannot be opened\n";
	exit(1);
}


This post has been edited by Huzi94: 22 December 2009 - 01:17 PM

Was This Post Helpful? 0
  • +
  • -

#4 r.stiltskin  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1833
  • View blog
  • Posts: 4,927
  • Joined: 27-December 05

Re: File input/output problem

Posted 22 December 2009 - 01:29 PM

View PostHuzi94, on 22 Dec, 2009 - 03:14 PM, said:

Instead of
if (!clientFile)
{
	cerr<<"clients.txt cannot be opened\n";
	exit(1);
}



Use
if (clientFile.is_open())
{
	//read file
}
else
{
	cerr<<"clients.txt cannot be opened\n";
	exit(1);
}



Why?
Was This Post Helpful? 0
  • +
  • -

#5 xnewix  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 2
  • View blog
  • Posts: 204
  • Joined: 23-May 09

Re: File input/output problem

Posted 22 December 2009 - 02:46 PM

Quote

Why?


That's exactly what I was thinking.

if you want to convert a string to an int, you can use std::map

#include <string>
#include <map>
#include <vector>

class FileData {
private:
	std::map<std::string, int> numberData;
	std::vector<std::string> tempVector;
	std::string tempString;
public:
	FileData() {
		std::ifstream Cfile("numbers.txt");
		while(!Cfile.eof()) {
			Cfile >> tempString;
			tempVector.push_back(tempString);
		}
		for(int i=0; i< tempVector.size(); i++) {
			numberData[tempVector[i]] = i;		
		}
	}

int getnumber(string& number) //! Use this function to convert the strings
	{
		int converted_number =  numberData[number];
		return converted_number;			
	}
}; 



hum, why didn't I think of this before . . :)

This post has been edited by xnewix: 22 December 2009 - 03:20 PM

Was This Post Helpful? 0
  • +
  • -

#6 r.stiltskin  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1833
  • View blog
  • Posts: 4,927
  • Joined: 27-December 05

Re: File input/output problem

Posted 22 December 2009 - 04:56 PM

View Postxnewix, on 22 Dec, 2009 - 04:46 PM, said:

Quote

Why?

if you want to convert a string to an int, you can use std::map
...


Does that have anything at all to do with the OP's problem?
Was This Post Helpful? 0
  • +
  • -

#7 xnewix  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 2
  • View blog
  • Posts: 204
  • Joined: 23-May 09

Re: File input/output problem

Posted 22 December 2009 - 05:56 PM

Quote

In the file, the two inputs are already printed there but the numbers 5 and 9.98 are printed in other formats (hexadecimal maybe?) and there are some weird characters in each record
like this : and F


Quote

PS: when you print the file to your console, the "weird characters" occur because the numbers are not chars (single-byte data), they are ints and doubles (multi-byte data) and your shell is printing the individual bytes that make them up as if they were chars.


Apparently, yes. Or maybe I mis-understood. The trouble you get for trying to help these days. Don't know why I bother. Besides, at least my post is more relivant that yours.

This post has been edited by xnewix: 22 December 2009 - 05:58 PM

Was This Post Helpful? 0
  • +
  • -

#8 Bench  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 857
  • View blog
  • Posts: 2,343
  • Joined: 20-August 07

Re: File input/output problem

Posted 23 December 2009 - 03:18 AM

The >> and << operators know how to automatically convert between strings and numeric types; a stream will have its fail flag set if it tries to read some non-numeric data into a numeric type.

so to write a string or numeric data to a text file with each item of data separated with a space
std::string str = "hello";
int num = 5;
double d = 12.345; 
std::ofstream outfile("myfile.txt");

if( outfile.is_open() )
    outfile << str << ' ' << num << ' ' << d << std::endl; 


Reading that same data back in:
std::string str;
int num;
double d;
std::ifstream infile("myfile.txt");

if( infile >> str >> num >> d )
    // Data read successfully


In the article I wrote recently discussing file input and EOF, there's a short explanation and example on reading simple delimited data http://www.dreaminco...topic145699.htm

This post has been edited by Bench: 23 December 2009 - 03:20 AM

Was This Post Helpful? 0
  • +
  • -

#9 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6092
  • View blog
  • Posts: 23,612
  • Joined: 23-August 08

Re: File input/output problem

Posted 23 December 2009 - 06:27 AM

Excellent tutorial, Bench!
Was This Post Helpful? 0
  • +
  • -

#10 r.stiltskin  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1833
  • View blog
  • Posts: 4,927
  • Joined: 27-December 05

Re: File input/output problem

Posted 23 December 2009 - 07:24 AM

Guys, the OP's problem had nothing to do with type conversion. He was simply looking at the file to see why his data wasn't being printed.
Was This Post Helpful? 0
  • +
  • -

#11 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6092
  • View blog
  • Posts: 23,612
  • Joined: 23-August 08

Re: File input/output problem

Posted 23 December 2009 - 07:32 AM

Oh, I know, r....I just noticed Bench's tutorial :)
Was This Post Helpful? 0
  • +
  • -

#12 xenoslash  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 89
  • Joined: 19-August 09

Re: File input/output problem

Posted 25 December 2009 - 07:44 PM

Another problem guys!! I don't know if I should make a new topic, but since I don't know what I should write for the title, might as well put it here
This one is kinda weird

Problem:


Here is the code

client.h
#ifndef CLIENTDATA_H
#define CLIENTDATA_H

#include <string>
using namespace std;

class ClientData
{
public:
	ClientData(string="", string ="", int=0, double=0.0);

	void setAccountNumber(int);
	int getAccountNumber()const;

	void setBalance(double);
	double getBalance()const;

	void setFirstName(string);
	string getFirstName();

	void setLastName(string);
	string getLastName();

	void print();
private:
	int accountNumber;
	double balance;
	char firstName[10];
	char lastName[15];

};

#endif




ClientData.cpp
#include "ClientData.h"
#include <iostream>
using namespace std;


ClientData::ClientData(string first, string last, int number, double money)
{
	setFirstName(first);
	setLastName(last);
	setAccountNumber(number);
	setBalance(money);
}

void ClientData::setAccountNumber(int number)
{
	accountNumber=(number>0 && number<=100) ? number : 0;
}

int ClientData::getAccountNumber()const
{
	return accountNumber;
}

void ClientData::setBalance(double money)
{
	balance= (money>=0.0) ? money : 0; 
}

double ClientData::getBalance()const
{
	return balance;
}

void ClientData::setFirstName(string first)
{
	const char* firstNameValue=first.data();
	int length= (first.size()<10) ? first.size() : 9;
	strncpy (firstName, firstNameValue, 14);
	firstName[length]='\0';
}

string ClientData::getFirstName()
{
	return firstName;
}

void ClientData::setLastName(string last)
{
	const char* lastNameValue=last.data();
	int length= (last.size()<15) ? last.size() : 14;
	strncpy (lastName, lastNameValue, 14);
	lastName[length]='\0';
}

string ClientData::getLastName()
{
	return lastName;
}

void ClientData::print()
{
	cout<<"Name:"<<getFirstName()<<' '<<getLastName()<<endl;
	cout<<"Balance:"<<getBalance()<<endl;
	cout<<"Account Number:"<<getAccountNumber()<<endl;
}




test.cpp

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
#include "ClientData.h"
using namespace std;

enum Choice {PRINT=1, UPDATE, NEW , DELETE, END};

int enterChoice();
void createTextFile( fstream& );
void updateRecord( fstream& );
void newRecord( fstream& );
void deleteRecord( fstream& );
void outputLine( ostream&,  ClientData & );
int getAccount( const char * const );


int main()
{
	ofstream outCredit( "credits.txt", ios::binary | ios::app );

	 // exit program if ofstream could not open file
	 if ( !outCredit )
	 {
		cerr << "File could not be opened." << endl;
		exit( 1 );
	 } // end if

	 ClientData blankClient; // constructor zeros out each data member

	 // output 100 blank records to file
	 for ( int i = 0; i < 100; i++ )
		outCredit.write( reinterpret_cast< const char * >( &blankClient ),
		   sizeof( ClientData ) );	
	outCredit.close();
	

	fstream inOutCredit("credits.txt", ios::in | ios::out | ios::binary);

	if (!inOutCredit)
	{
		cerr<<"File clients.txt cannot be opened."<<endl;
		exit(1);
	}

	int choice;

	while ((choice=enterChoice())!=END)
	{
		switch (choice)
		{
			case PRINT:
				createTextFile(inOutCredit);
				break;
			case UPDATE:
				updateRecord(inOutCredit);
				break;
			case NEW:
				newRecord(inOutCredit);
				break;
			case DELETE:
				deleteRecord(inOutCredit);
				break;
			default:
				cerr<<"Incorrect Choice"<<endl;
				break;
		}
	inOutCredit.clear();
	}

	return 0;
}

int enterChoice()
{
	int input;
	
	cout<<"1.PRINT"<<endl
		<<"2.UPDATE"<<endl
		<<"3.NEW"<<endl
		<<"4.DELETE"<<endl
		<<"5.END"<<endl; 

	cin>>input;
	return input;
}

void createTextFile( fstream &readFromFile)
{

	ofstream outClientFile ("clients.txt",ios::out);

	if (!outClientFile.is_open())
	{
		cerr<<"clients.txt cannot be opened for output";
		exit(1);
	}

	outClientFile << left << setw( 10 ) << "Account" << setw( 16 )
				  << "Last Name" << setw( 11 ) << "First Name" << right	 
				  << setw( 10 ) << "Balance" << endl;  

	readFromFile.seekg(0);

	ClientData tempClient;
	readFromFile.read(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));

	while (!readFromFile.eof())
	{
		if ( tempClient.getAccountNumber() != 0 )  // skip empty records
			outputLine( outClientFile, tempClient );

		// read next record from record file					 
		readFromFile.read( reinterpret_cast< char * >( &tempClient ),sizeof( ClientData ) );						 
	}
	outClientFile.close();
}

void updateRecord( fstream& updateFile)
{
	int accountNumber = getAccount( "Enter account to update" );

	updateFile.seekp((accountNumber-1)*sizeof(ClientData));

	ClientData tempClient;
	updateFile.read(reinterpret_cast<char*>(&tempClient), sizeof(ClientData));

	if (tempClient.getAccountNumber()!=0)
	{
		tempClient.print();
		cout<<endl;

		cout<<"Enter charge (+) or payment (-):";
		double transaction;
		cin>>transaction;
		
		double oldBalance=tempClient.getBalance();
		tempClient.setBalance(oldBalance+transaction);
		tempClient.print();
		cout<<endl;

		updateFile.seekp((tempClient.getAccountNumber()-1)*sizeof(ClientData));

		updateFile.write(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));
	}
	else 
		cerr<<"Account #"<<accountNumber<<" does not exist."<<endl;
}

void newRecord( fstream& insertInFile)
{

	int accountNumber=getAccount("Enter a new account number:");

	insertInFile.seekg((accountNumber-1)*sizeof(ClientData));

	ClientData tempClient;
	insertInFile.read(reinterpret_cast<char*>(&tempClient), sizeof(ClientData));

	if (tempClient.getAccountNumber()==0)//if record is empty
	{
		char lastName[15];			
		char firstName[10];
		double balance;

		cout << "Enter lastname, firstname, balance\n? ";
		cin >> setw( 15 ) >> lastName;
		cin >> setw( 10 ) >> firstName;
		cin >> balance;

		// use values to populate account values
		
		tempClient.setFirstName( firstName );  //PROBLEM!! LAST TIME ORDER IS SWITCHED
		tempClient.setLastName( lastName );	//SETLASTNAME() NOT WORKING!!!
		tempClient.setBalance( balance );
		tempClient.setAccountNumber( accountNumber );
		
		insertInFile.seekp((accountNumber-1)*sizeof(ClientData));

		insertInFile.write(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));
	}
	else 
		cerr<<"Account #"<<accountNumber<<" has already existed"<<endl;
}

void deleteRecord( fstream &deleteFromFile)
{
	int accountNumber=getAccount("Enter an account to delete");

	deleteFromFile.seekg((accountNumber-1)*sizeof(ClientData));

	ClientData tempClient;
	deleteFromFile.read(reinterpret_cast<char*>(&tempClient),sizeof(ClientData));

	if (tempClient.getAccountNumber()!=0)
	{
		ClientData blankClient;

		deleteFromFile.seekp((accountNumber-1)*sizeof(ClientData));
		deleteFromFile.write(reinterpret_cast<char*>(&blankClient),sizeof(ClientData));
	
		cout<<"Account #"<<accountNumber<<" deleted."<<endl;
	}
	else	
		cerr<<"File to be deleted does not exist."<<endl;

}

void outputLine( ostream& output, ClientData & record)
{
	output << left << setw( 10 ) << record.getAccountNumber()
		   << setw( 16 ) << record.getLastName()
		   << setw( 11 ) << record.getFirstName()
		   << setw( 10 ) << setprecision( 2 ) << right << fixed
		   << showpoint << record.getBalance() << endl;
}

int getAccount( const char * const prompt)
{
	cout<<prompt<<endl;

	int accountNumber=1;
	do
		{
		cout<<"1-100 only"<<endl;
		cin>>accountNumber;
		}
	while (accountNumber<1 || accountNumber>100);

	return accountNumber;
}



The problem lies in this line


		tempClient.setFirstName( firstName );  //PROBLEM!! LAST TIME ORDER IS SWITCHED
		tempClient.setLastName( lastName );	//SETLASTNAME() NOT WORKING!!!
		tempClient.setBalance( balance );
		tempClient.setAccountNumber( accountNumber );



The above code works but this one

		tempClient.setLastName( lastName );	//SETLASTNAME() NOT WORKING!!!
		tempClient.setFirstName( firstName );  
		tempClient.setBalance( balance );
		tempClient.setAccountNumber( accountNumber );



doesn't work.

When I tested the second code with this line

cout<<tempClient.getLastName(lastName);



It prints nothing, but firstName functions still work fine.
I tested the member function set and getLastName() and they both work fine.

This is my second problem solved by just swapping two code lines. Does this have anything to do with memory allocation?
Was This Post Helpful? 0
  • +
  • -

#13 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6092
  • View blog
  • Posts: 23,612
  • Joined: 23-August 08

Re: File input/output problem

Posted 25 December 2009 - 07:52 PM

I have just one question for you. One simple question.

Is there a legitimate reason for mixing C++ strings and C character arrays? If you can use C++ strings...JUST USE THEM!!! Why would just go through all these machinations???
Was This Post Helpful? 0
  • +
  • -

#14 xenoslash  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 89
  • Joined: 19-August 09

Re: File input/output problem

Posted 25 December 2009 - 08:30 PM

Tried that and got this execution (or is it runtime??) time error
Debug Assertion Failed
Expression: dst!=NULL

This is the new code

void ClientData::setLastName(string last)
{
lastName=last;
}

Much simpler!! XD

But still, why the error??
I have converted the data members to string types too
Was This Post Helpful? 0
  • +
  • -

#15 xenoslash  Icon User is offline

  • D.I.C Head

Reputation: 3
  • View blog
  • Posts: 89
  • Joined: 19-August 09

Re: File input/output problem

Posted 25 December 2009 - 08:52 PM

Tried that and got this execution (or is it runtime??) time error
Debug Assertion Failed
Expression: dst!=NULL

This is the new code

void ClientData::setLastName(string last)
{
lastName=last;
}

Much simpler!! XD

But still, why the error??
I have converted the data members to string types too
Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3