Output from file using function - c++

the title says it all
This is my code:
I have a class called House, where i define the values.
class HOUSE
{
public:
int id;
string 1;
string 2;
string 3;
int an;
};
template<class Type>
class table
{
public:
vector<Type> V;
//double inceput;
//double sfirsit;
//int comparatii;
//int interschimbari;
public:
table();
void print();
void liniar();
};
template<class Type>
table<Type>::table()
{
ifstream file("file.txt");
ifstream file1("file1.txt");
if (file.fail() || file1.fail())
{
cerr << "Eroare la deschiderea fisierului!" << endl;
_getch();
exit(1);
}
HOUSE* value = new HOUSE;
while (!file.eof() || file1.fail())
{
file >> value->id;
file >> value->tara;
file >> value->brand;
file >> value->culoare;
file >> value->an;
this->V.push_back(*value);
}
file.close();
}
The print function for the values
template<class Type>
void table<Type>::print()
{
cout << endl << setw(50) << "AFISAREA DATELOR" << endl;
cout << setw(5) << "Id" << setw(15) << "1" << setw(20) << "2" << setw(17) << "3" << setw(20) << "an" << endl << endl;
for (int i = 0; i < this->V.size(); i++)
{
cout << setw(5) << this->V.at(i).id << setw(15)
<< this->V.at(i).1<< setw(17)
<< this->V.at(i).2<< setw(17)
<< this->V.at(i).3<< setw(25)
<< this->V.at(i).an << endl;
}
cout << endl << "Dimensiunea tabelului n= " << V.size() << endl;
}
{
file >> value->id;
file >> value->1;
file >> value->2;
file >> value->3;
file >> value->an;
this->V.push_back(*value);
}
file.close();
}
in main
int main() {
table<MOBILE>* file = new table<MOBILE>();
table<MOBILE>* file1 = new table<MOBILE>();
file ->print();
file1 ->print();
This is full code as requested.
Need make it somehow print the data from file1 and file2 .
thx
The problem is idk if called right. Because
file ->print();
file1 ->print();
both print data from the file only
There are no errors at all

There's lots and lots wrong with your code. but I'm going to ignore that and just answer what I think is your actual question.
You want two table objects, one of which reads from file.txt and the other reads from file1.txt. To do that you should pass the file name into the table::table constructor, so it knows which file to read from. Like this
template<class Type>
class table
{
...
public:
table(const char* filename); // constructor takes filename parameter
...
};
template<class Type>
table<Type>::table(const char* filename)
{
ifstream file(filename); // open filename
if (file.fail())
...
int main() {
table<MOBILE>* file = new table<MOBILE>("file.txt"); // read from file.txt
table<MOBILE>* file1 = new table<MOBILE>("file1.txt"); // read from file1.txt
file ->print();
file1 ->print();
}

Related

function to stream certain name and number from txt file

i made a file named clientFile.txt
the file contain this clientFile.txt. Content:
abcd abcd 123 1607325695
A AI 123 1607327861
the function below should show the content of the text file when the function called.
void displayFile()
{
string str1;
string str2;
string fileN = "clientFile.txt";
ifstream myfilein;
myfilein.open("clientFile.txt");
double balance;
int numAct = 0;
time_t transTime;
if(!myfilein){
cerr << "FIle could not be opened" << endl;
exit(1);
}
while(myfilein >> str1 >> str2 >> balance >> transTime){
cout << setw(15) << str1 << ' ' << setw(15) << str2 << ' '
<< setw(7) << balance << " " << ctime(&transTime);
numAct++;
}
myfilein.close();
cout << "Number of records in the file " << fileN << ": " << numAct << endl;
}
but when i call it on this int main:
int main(){
ofstream myfileout;
ifstream myfilein;
string firstName,lastName;
int i=0;
string FN[1000],LN[1000];
double actBalance,AB[1000];
time_t currentTime,CT[1000];
myfilein.open ("clientFile.txt");
void displayFile();
if(myfilein.fail()){
cout<<"Creating new files"<<endl;
myfileout.open ("clientFile.txt",ios::out);
myfileout.close();
exit(1);
}
while(myfilein>>firstName>>lastName>>actBalance>>currentTime){
FN[i]=firstName;
LN[i]=lastName;
AB[i]=actBalance;
CT[i]=currentTime;
i++;
}
myfileout.open("clientFile.txt",ios::app);
cout<<"Enter first name, last name, and balance:"<<endl;
while(cin>>firstName>>lastName>>actBalance){
createRecord(myfileout, firstName,lastName,actBalance);
}
void displayFile();
myfileout.close();
}
it didnt show me any of the file content.
can you guys help me?
im using dev c++ with TDM-GCC 4.9.2 64-bit release
In last lines of main() you just need to change
void displayFile();
to
displayFile();
Because with void you're declaring a function, not calling it.

When reading in a .txt file in c++, how do I change a number that's stored in the .txt file as "365048" to "36, 50, 48" using a dynamic array?

I have been trying to separate a number stored in a .txt file as "365048" to "36, 50, 48" when it has been read into my program using a dynamic array and i'm not sure where I am going wrong. The variable i'm having the issue with is int* purchases.
Code from Main.cpp
// Repeat_Assessment_C++_Aisling.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include "Customer.h"
using namespace std;
void OutputFileStream();
void parseLine(const string& str);
void InputFileStream();
//void printActions();
void OutputFileStream()
{
cout << "Creating and writing to file: Customer.txt" << endl;
ofstream outStream("customers.txt"); // write mode (overwrites existing data)
if (outStream.good())
{
int customerID = 150033;
outStream << "This is a line of text.\n";
outStream << "This is another line of text.\n";
outStream << "This is a line of text.\n";
int numOfPurchases = 4;
int purchases = 0;
outStream << customerID << "Mr" << "Jack" << "New" << numOfPurchases << purchases << endl;
outStream.close(); // close file
cout << "File written.\n" << endl;
}
else
cout << "Unable to open file";
}
void parseLine(const string& str) {
stringstream strStream(str); //create string stream from the string
// int customerID;
string title;
string name;
string type;
//int numOfPurchases;
//int purchases;
string s;
int customerID = 150033;
getline(strStream, s, ';');
customerID = stoi(s);
getline(strStream, title, ';');
getline(strStream, name, ';');
getline(strStream, type, ';');
int numOfPurchases = 4;
getline(strStream, s, ';');
numOfPurchases = stoi(s);
int purchases = 0;
getline(strStream, s, ';');
purchases = stoi(s);
int* purchasesArray = new int[3];
purchasesArray[0] = (purchases & (255 << 24)) >> 24;
purchasesArray[1] = (purchases & (255 << 16)) >> 16;
purchasesArray[2] = (purchases & (255 << 8)) >> 8;
for (int i = 0; i < 3; i++)
{
int purchasesArray[3];
}
cout << " CustomerID: " << customerID << "Title:" << title << " Name: " << name << " Type:" << type << " Number of Purchases: " << numOfPurchases << "Purchases: " << purchases << endl;
}
void InputFileStream() {
cout << "Reading from a semi-colon delimited txt file" << endl;
string line;
ifstream inStream("customers.txt"); //opens file as an input file stream
if (inStream.good()) //if the file is opened successfully and not empty
{
while (getline(inStream, line)) //reads line until false return
{
parseLine(line);
}
inStream.close();
}
else
cout << "unable to open file or the file is empty!";
}
int main()
{
InputFileStream();
Customer cust1;
cust1.setCustomerID(150032);
cust1.setTitle("Mr");
cust1.setName("Joey");
cust1.setNumOfPurchases(3);
cust1.setPurchases(366, 352, 334);
cust1.setType("New");
cout << cust1.getCustomerID() << endl;
cout << cust1.getTitle() << endl;
cout << cust1.getName() << endl;
cout << cust1.getNumOfPurchases() << endl;
cout << cust1.getPurchases() << endl;
cout << cust1.getType() << endl;
return 0;
}
Code from Customer.h
#pragma once
#include<iostream>
using namespace std;
#include<string>
class Customer
{
private:
int customerID;
string title;
string name;
int numOfPurchases;
int* purchases;
string type;
public:
Customer(); // default constructor
Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type);
//copy overload assignment
Customer& operator=(Customer& otherCustomer);
Customer(const Customer& source);
~Customer(); //destructor
//Getters and Setters
void setCustomerID(int customerID);
void setTitle(string title);
void setName(string name);
void setNumOfPurchases(int numOfPurchases);
void setPurchases(int purchase1, int purchase2, int purchase3);
void setType(string type);
int getCustomerID();
string getTitle();
string getName();
int getNumOfPurchases();
int* getPurchases();
string getType();
void printCustomer() {
cout << customerID << "," << title << "," << name << "," << numOfPurchases << "," << purchases << "," << type << endl;
}
friend std::ostream& operator<<(std::ostream& out, Customer& customer); // overloaded operator<<
friend istream& operator>> (istream& in, Customer& customer); // overloaded operator >>
};
Code from Customer.cpp
#include "Customer.h"
#include <iostream>
#include <string>
#include<utility>
using namespace std;
//default constructor
Customer::Customer() {
}
//Full constructor
Customer::Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type)
{
this->customerID = customerID;
this->title = title;
this->name = name;
this->numOfPurchases = numOfPurchases;
purchases = new int[3];
purchases[0] = purchase1;
purchases[1] = purchase2;
purchases[2] = purchase3;
this->type = type;
}
Customer::Customer(const Customer& source) //copy constructor
{
cout << "copy constructor called" << endl;
this->customerID = source.customerID;
this->title = source.title;
this->name = source.name;
this->numOfPurchases = source.numOfPurchases;
this->purchases = new int[3];
purchases[0] = source.purchases[0];
purchases[1] = source.purchases[1];
purchases[2] = source.purchases[2];
this->type = source.type;
}
//overloaded assignment operator=
Customer& Customer::operator= (Customer& otherCustomer)
{
cout << "Overloaded assignment operator= called" << endl;
//self-assignment guard
if (this == &otherCustomer)
return *this; //refernce to the same object
// copy data from the source (rhs) to this object (the destination)
name = otherCustomer.name;
//must make a new scores object to store a copy of the other student
if (purchases != nullptr)
delete[] purchases;
purchases = new int[3];
for (int i = 0; i < 3; i++) {
purchases[i] = otherCustomer.purchases[i];
}
//return this existing object so we can chain this operator
return *this;
}
Customer::~Customer() {
cout << "Destructor ~Customer called" << endl;
delete[] purchases;
}
// Overloaded insertion operator (Outputs Character object data as an output stream)
// Defined in header file as a "friend" function, as it is not a member function
//
ostream& operator<<(ostream& out, Customer& customer)
{
cout << "Customer details ( output by insertion operator<< )" << endl;
cout << "Customer ID: " << customer.customerID << endl;
cout << "Title: " << customer.title << endl;
cout << "Name: " << customer.name << endl;
cout << "Number of purchases: " << customer.numOfPurchases << endl;
cout << "Purchases: ";
for (int i = 0; i < 3; i++)
{
if (i > 0) cout << ",";
cout << customer.purchases[i];
}
cout << "Type: " << customer.type << endl;
return out;
}
istream& operator>> (istream& in, Customer& customer)
{
cout << "Enter Customer details ( using the extraction operator>> )" << endl;
cout << "Enter Customer ID: " << endl;
cin >> customer.customerID;
cout << "Enter Title: " << endl;
getline(cin, customer.title);
cout << "Enter Name: " << endl;
getline(cin, customer.name);
cout << "Enter Number of Purchases: ";
cin >> customer.numOfPurchases;
cout << "Enter Purchases: ";
cin >> customer.purchases[0];
cin >> customer.purchases[1];
cin >> customer.purchases[2];
cout << "Enter Type";
getline(cin, customer.type);
cout << endl;
return in;
}
int Customer::getCustomerID()
{
return customerID;
}
string Customer::getTitle()
{
return title;
}
string Customer::getName()
{
return name;
}
int Customer::getNumOfPurchases()
{
return numOfPurchases;
}
int* Customer::getPurchases()
{
return purchases;
}
string Customer::getType()
{
return type;
}
void Customer::setCustomerID(int customerID)
{
if (customerID < 1) {
cout << "Customer ID has to be equal to 1 or more" << endl; //Changed all the "throw invalid_argument" messages to cout as they were causing an issue with my main.cpp file and an abort message kept appearing every time I ran my main.cpp file.
}
this->customerID = customerID;
}
void Customer::setTitle(string title)
{
if (title.length() < 2) {
cout << "Title has to be more than or equal to 2 characters" << endl;
}
this->title = title;
}
void Customer::setName(string name)
{
if (name.length() < 4) {
cout << "Length of name should be more than or equal to 4 characters" << endl;
}
this->name = name;
}
//Got help ith this on stack overflow as I was using "&&" instead of using "||" for the if statement
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases <0 || numOfPurchases > 10000){
cout << "Number of purchases should be between 0 to 10000" << endl;
}
this->numOfPurchases = numOfPurchases;
}
void Customer::setPurchases(int purchase1, int purchase2, int purchase3)
{
if (purchase1 < 0 || purchase2 < 0 || purchase3 < 0) {
cout << "Purchases must be more than or equal to zero" << endl;
}
}
//Got help from stack overflow on comparing strings as I originally didnt use "type.compare"
void Customer::setType(string type) {
if (type.compare("New") !=0 || type.compare("Either") !=0) {
cout << "Type of purchase has to be New or Either" << endl;
}
}
Text in my customers.txt file:
150034;Mr;Sean Brennan;New;5;365048;\n
150035;Mrs;Aisling Smith;Regular;6;375149;\n
150036;Mr;John Smith;New;7;385250;\n
150037;Mrs;Sharon Hanratty;Regular;8;395351;
Trouble seems to be that you are trying to divide input into its hexadecimal digits and it looks like you are looking for decimal digits.
May be you can do something like following:
purchasesArray[0] = purchases / 10000;
purchasesArray[1] = (purchases / 100) % 100;
purchasesArray[2] = purchases % 100;
instead of
purchasesArray[0] = (purchases & (255 << 24)) >> 24;
purchasesArray[1] = (purchases & (255 << 16)) >> 16;
purchasesArray[2] = (purchases & (255 << 8)) >> 8;
Note: If your input is pretty big, above solution can be bad performancewise.
Note 2: Even if you really want hexadecimal digits, your parsing is problematic.
Edit for note 2:
To parse a 6 digit hexadecimal number you might do this:
purchasesArray[0] = (purchases & (255 << 16)) >> 16;
purchasesArray[1] = (purchases & (255 << 8)) >> 8;
purchasesArray[2] = purchases & 255;
your code seems to parse first 6 digits of an 8 digit hex number.
That is why I called it problematic.

How to open and read a file based on user input c++

I have an assignment that wants me to write a program that reads a text file, then outputs a modified version of that file using a version of Ceasar cipher that shifts the characters of the file that the user calls based on the shift amount that they input. For example if my file reads "hi" and they shift it by 1 it should read "ij". But when I run the program it doesnt recognize when I call in1 or out1 and I just get an error message. Can anyone help me figure out what I'm doing wrong or offer any advice on how to move forward? Thank you in advance!
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cctype>
using namespace std;
int main()
{
//Declare user variables
int shift, file1chars = 0;
char filename[25];
ifstream in1;
ofstream out1;
do
{
in1.clear(); //clear status flags
//Prompt user to enter name of input file and amount of shift
cout << "Please enter the name of the input file." << endl;
cout << "Filename: ";
cin >> filename;
//Open file name
in1.open(filename);
//Error message if no file
if (!in1)
cout << "That is not a valid file. Try again\n";
} while (!in1);
do
{
out1.clear(); //clear status flags
//prompt user to input out file
cout << "Please enter the name of the output file." << endl;
cout << "Filename: ";
cin >> filename;
out1.open(filename);
//Error message if no file
if (!out1)
cout << "That is not a valid file. Try again\n";
} while (!out1);
//write some code to the input file
in1 >> "hi"
//write the integers in a different order to the output file
out1 << //idk where to go from here to initiate shift
//prompt user to enter shift
cout << "Please intput the shift amount: ";
cin >> shift;
cout << "Processing complete" << endl;
//Call file (?)
//Tell user file input is complete and is now printing statistics
cout << "\nShifted input file Complete. Now printing statistics " << endl;
//Show statistics for file
cout << "\nStatistics for file: " << filename << endl;
cout << "------------------------------------------------";
//Show characters in file and stats before shift
cout << "\n\nTotal # of characters in file: " << file1chars << endl;
cout << "Statistics before shift: " << endl;
//Show file before shift
//Show user stats after shift
cout << "\nStatistics after shift: " << endl;
//File after shift
//Close files
out1.close();
in1.close();
return 0;
}
Instead of looking at your code for line by line to see where the problem(s) could be, I ask you to think about your requirements and write code that expresses the intent as closely as possible. Create functions that follow the intended functionality.
Get the input file name.
Get the output file name.
Read the contents of the input file.
Transform the contents of the input file to create the output string.
Write the output string to the output file.
In pseudo code,
int main()
{
infile = get_input_filename()
outfile = get_output_filename()
contents = get_file_contents(infile)
output = transform_input(contents)
write_output(outfile, output)
}
Convert that to C++ code:
// Declare the functions.
std::string get_input_filename();
std::string get_output_filename();
std::string get_file_contents(std::string const& infile)
std::string transform_input(std::string const& contents)j
void write_output(std::string const& outfile, std::string const& output);
// Use them in main.
int main()
{
std::string infile = get_input_filename();
std::string outfile = get_output_filename();
std::string contents = get_file_contents(infile);
std::string output = transform_input(contents);
write_output(outfile, output);
}
// Implement the functions.
std::string get_input_filename()
{
std::string filename;
cout << "Please enter the name of the input file." << endl;
cout << "Filename: ";
cin >> filename;
return filename;
}
std::string get_output_filename()
{
std::string filename;
cout << "Please enter the name of the output file." << endl;
cout << "Filename: ";
cin >> filename;
return filename;
}
std::string get_file_contents(std::string const& infile)
{
std::ifstream inf(infile);
std::string contents;
int c;
while ( (c = inf.get()) != EOF )
{
contents += c;
}
return contents;
}
std::string transform_input(std::string const& contents)
{
std::string res;
// Do the needful to transform contents to res.
return res;
}
void write_output(std::string const& outfile, std::string const& output)
{
std::ofstream outf(outfile);
outf.write(output.c_str(), output.size();
}
If you are able to use a class or struct and functions I would propose something like this:
main.cpp
#include <string>
#include <iostream>
#include <fstream>
#include "CaesarShift.h"
int main() {
std::string filename;
std::cout << "Please enter the name of the input file. ";
std::cin >> filename;
std::ifstream fileIn;
std::string text;
fileIn.open( filename );
if ( !fileIn.is_open() ) {
std::cout << "Failed to open file: " << filename << "." << std::endl;
}
fileIn >> text;
fileIn.close();
CaesarText caesarText;
caesarText.addText( text );
std::cout << "Contents of the Caesar Text before peforming a Caesar Shift:\n"
<< caesarText << std::endl;
int amount = 0;
std::cout << "Please enter the amount to shift the text ";
std::cin >> amount;
std::cout << "Now performing the Caesar Shift: " << std::endl;
caesarShift( caesarText, amount );
std::cout << "Caesar Text after performing a Caesar Shift:\n"
<< ceasarText << std::endl;
std::ofstream fileOut;
fileOut.open( std::string( "shifted_" + filename ) );
if ( !fileOut.is_open() ) {
std::cout << "Failed to open shifted_" << filename << std::endl;
}
// Uncomment to print original text to file otherwise only modified text will be printed.
// fileOut << caesarText.originalText() << std::endl;
fileOut << caesarText.shiftedText() << std::endl;
fileOut.close();
system( "PAUSE" );
return 0;
}
CaesarShift.h
#ifndef CAESAR_SHIFT_H
#define CAESAR_SHIFT_H
class CaesarText {
std::string _originalText;
std::string _shiftedText;
public:
caesarText() = default;
explicit CeasarText( const std::string& text ) :
_originalText( text ) {}
void addText( const std::string& text ) {
_originalText = text;
}
std::string originalText() const {
return _originalText;
}
std::string shiftedText() const {
return _shiftedText;
}
friend void caesarShift( caesarText& c, int amount );
friend std::ostream& operator<<( std::ostream& out, const caesarText& ceasarText );
};
#endif // !CAESAR_SHIFT_H
CaesarShift.cpp
#include "CaesarShift.h"
#include <string>
#include <iostream>
#include <algorithm>
// Overloaded ostream operator
std::ostream& operator<<( std::ostream& o, const CaesarText& c ) {
o << "Original Text: " << c._originalText << "\n";
o << "Shifted Text: " << c._shiftedText << "\n";
return o;
}
// public friend function (visible in main) not actually a part of the class
// but performs operations on it.
// To perform the Caesar Shift here are 3 possible variations of implementing the same task.
void caesarShift( Caesar Text& text, int amount ) {
// Bound amount to the number of characters in the alphabet
// the same value used in any of the three variations below.
amount %= 26;
// Older c++ style loop.
/*for ( std::size_t i = 0; i < text._originalText.length(); i++ ) {
char c = text._originalText[i] + amount;
text._shiftedText += c;
}*/
// Modern C++ style loop
/*for ( auto& c : text._originalText ) {
text._shiftedText += c + amount;
}*/
// std::transform( s1.begin, s1.end, back_inserter( s2 ), lamda as predicate );
/*std::transform( text._originalText.begin(), text._originalText.end(),
std::back_inserter( text._shiftedText ),
[amount]( unsigned char c ) -> unsigned char { return c + amount; }
);*/
}
As for the 3 different variations of performing the Caesar Shift you can just uncomment the appropriate block section.

Unable to opening file with ifstream

I'd like to get some assistance regarding the following line of code.
for the function constructArray,I'm unable to run it as shows the !aFile as true message but I have no idea what's the error.
Really appreciative of your assistance
Also how do I create inFile fileName with .txt,i've tried indentation with +".txt" but due to the file type in the argument i'm unable to do so.
Compiler run image: https://imgur.com/a/wkGwL
using namespace std;
enum NumType {Odd, Even};
struct Number
{
int no;
NumType type;
int oddDigits;
int evenDigits;
int sumDigits;
int noDigits;
};
// Create inFile data file with certain number of integers which are randomly generated
void constructInfile (fstream& aFile, char fileName[]);
// Read data from infile txt file and transfer to array of numbers
int constructArray (fstream& aFile,const char fileName[], Number ran[]);
/*
void processArray (Number [ ], int);
// Transfer information from array and store into output file called outfile txt with specific information format
void arrayToOutfile (fstream&, char [ ], Number [ ], int);
*/
const int MAX = 50;
int main()
{
srand(time(NULL));
fstream aFile;
char fileName [MAX];
cout << "Enter designated file name to be created" << endl;
cin >> fileName;
constructInfile (aFile,fileName);
Number ran[MAX];
int recNo = constructArray(aFile,fileName,ran);
cout << recNo << " of records transferred" << endl;
}
// Create inFile data file with certain number of integers which are randomly generated
void constructInfile (fstream& aFile,char fileName[]){
aFile.open(fileName, ios::out);
if(aFile.fail()){
cout << "File open unsuccessful" << endl;
aFile.close();
exit(1);
}
cout << "Begin creation of " << fileName << " file" << endl << endl;
int size = rand()%51+50;
for(int a = 0;a < size;a++){
aFile << rand()%1000+1 << endl;
}
cout << fileName << " file successfully created" << endl;
}
// Read data from infile txt file and transfer to array of numbers
int constructArray (fstream& aFile,const char fileName[], Number ran[]){
aFile.open (fileName, ios::in);
if (!aFile)
{
cout << fileName << " failed to open" << endl;
aFile.close ();
return 0;
}
cout << "Begin from " << fileName << " to array" << endl;
int i = 0;
char tabKey;
while (aFile >> ran[i].no)
{
aFile.get (tabKey); // read and discard
i++;
}
aFile.close ();
cout << fileName << " to array done" << endl;
return i;
}
You are opened a file in ios::out mode and never closed it!
Again you are trying to open the same file in ios::in mode. How a file could be opened twice in 2 different mode without properly closing the fstream?
You need to close the filestream inside the function constructInfile()!!!
You have opened the file but forget to close it. At the end of both of the functions, close the aFile. That should solve the problem.

Excessive spaces when writing a binary file

Trying to write a binary file from a struct. Unfortunately, it is writing out excessive spaces since my strings are all 20 characters long. I would use pointers, but my textbook specifically states not to use pointers (i.e. Remember: Only use fixed-size data members when writing to a binary file. Do not use pointers or classes that contain pointers as data members).
To make matters worse, the numbers I am trying to print out (i.e. 8 and 40) just appear as an 'A' and 'B'.
The output looks like this
Employee.dat (Binary file I am writing to)
Pauline Nordin A B
I want it to look like this, however.
Pauline Nordin 8.00 40.00
Here is my code:
Excerpt from protocol.cpp
//Open file
std::ifstream BinaryOpen("employee.txt", std::ios::in /*| std::ios::out*/ | std::ios::binary);
//Check if file is open
if(BinaryOpen.is_open())
{
//Priming read
BinaryOpen >> favoriteEmployees[numberOfEmployees].firstName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].lastName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hourlyWage;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hoursWorked;
numberOfEmployees++;
//Read file
while(!BinaryOpen.eof())
{
BinaryOpen >> favoriteEmployees[numberOfEmployees].firstName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].lastName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hourlyWage;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hoursWorked;
numberOfEmployees++;
//Close file
BinaryOpen.close();
}
//Write to binary file
std::ofstream BinaryWrite("employee.dat", std::ios::out | std::ios::binary);
//Check if file opened
if(BinaryWrite.is_open())
{
BinaryWrite.write(reinterpret_cast <char *>(favoriteEmployees),
sizeof(Employee) * numberOfEmployees);
//Close file
BinaryWrite.close();
}
else
std::cout << "\nWrite file did not open! " << std::endl;
}
else
std::cout << "\nFile did not open! " << std::endl;
}
Below are all the files for my program:
employee.txt (i.e. file I am reading from)
Pauline Nordin 8.00 40.00
main.cpp
#include <iostream>
#include "protocol.h"
#include "employee.h"
int main()
{
int menuChoice = 0;
int numberOfEmployees = 0;
//Create array of employees
Employee favoriteEmployees[NUMBER_OF_EMPLOYEES];
//To prevent garbage being printed out
for(int i = 0; i < BUFFER_LENGTH; i++)
{
favoriteEmployees[0].firstName[i] = 0;
favoriteEmployees[0].lastName[i] = 0;
favoriteEmployees[0].hourlyWage = 0;
favoriteEmployees[0].hoursWorked = 0;
}
PrintMenu();
GetMenuChoice(menuChoice);
ExecuteMenuChoice(menuChoice, favoriteEmployees, numberOfEmployees);
return 0;
}
protocol.h
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include "employee.h"
const int NUMBER_OF_EMPLOYEES = 10;
//Function declarations
void PrintMenu();
void GetMenuChoice(int &menuChoice);
void ExecuteMenuChoice(int menuChoice, Employee favoriteEmployees[], int &numberOfEmployees);
#endif
protocol.cpp
#include <fstream>
#include <iostream>
#include "employee.h"
#include "protocol.h"
//Function definitions
void PrintMenu()
{
std::cout << "\n\nChapter 17 -- Learn By Doings " << std::endl;
std::cout << "\n1. Learn By Doing 17.2 " << std::endl;
std::cout << "2. Learn By Doing 17.3 " << std::endl;
std::cout << "3. Learn By Doing 17.4 " << std::endl;
std::cout << "4. Exit " << std::endl;
std::cout << ' ' << std::endl;
}
void GetMenuChoice(int &menuChoice)
{
std::cin >> menuChoice;
}
void ExecuteMenuChoice(int menuChoice, Employee favoriteEmployees[], int &numberOfEmployees)
{
switch(menuChoice)
{
case 1:
{
//Open file in append mode
std::ifstream BinaryOpen("name.txt", std::ios::app | std::ios::binary);
//Open file in write mode
/*std::ofstream BinaryOpen("name.txt", std::ios::out | std::ios::binary);*/
//Check if file is open
if(BinaryOpen.is_open())
{
//Perform appropriate file operatings
std::cout << "\nFile opened! " << std::endl;
//Close file
BinaryOpen.close();
}
//Else
else
std::cout << "\nFile did not open! " << std::endl;
}
break;
case 2:
{
//Open file
std::ifstream BinaryOpen("employee.txt", std::ios::in /*| std::ios::out*/ | std::ios::binary);
//Check if file is open
if(BinaryOpen.is_open())
{
//Priming read
BinaryOpen >> favoriteEmployees[numberOfEmployees].firstName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].lastName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hourlyWage;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hoursWorked;
numberOfEmployees++;
//Read file
while(!BinaryOpen.eof())
{
BinaryOpen >> favoriteEmployees[numberOfEmployees].firstName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].lastName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hourlyWage;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hoursWorked;
numberOfEmployees++;
//Close file
BinaryOpen.close();
}
//Write to binary file
std::ofstream BinaryWrite("employee.dat", std::ios::out | std::ios::binary);
//Check if file opened
if(BinaryWrite.is_open())
{
BinaryWrite.write(reinterpret_cast <char *>(favoriteEmployees),
sizeof(Employee) * numberOfEmployees);
//Close file
BinaryWrite.close();
}
else
std::cout << "\nWrite file did not open! " << std::endl;
}
else
std::cout << "\nFile did not open! " << std::endl;
}
break;
case 3:
break;
case 4:
break;
default:
std::cout << "\nInvalid input. Please enter an integer from 1 to 4. " << std::endl;
}
}
**employee.h**
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
const int BUFFER_LENGTH = 20;
struct Employee
{
char firstName[BUFFER_LENGTH];
char lastName[BUFFER_LENGTH];
float hourlyWage;
float hoursWorked;
};
#endif
This is why it's printing garbage:
BinaryWrite.write(reinterpret_cast <char *>(favoriteEmployees),
sizeof(Employee) * numberOfEmployees);
Those probably aren't spaces you are seeing, but NULL characters or other unprintables.
What you need to do is write the file fields:
BinaryWrite << favoriteEmployees[i].firstName << " ";
BinaryWrite << favoriteEmployees[i].lastName << " ";
BinaryWrite << std::setprecision(2) << favoriteEmployees[i].hourlyWage << " ";
BinaryWrite << std::setprecision(2) << favoriteEmployees[i].hoursWorked << std::endl;
It's probably a bit misleading to call these binary files, because they really just contain text. An actual binary file would contain fixed-length, length-prefixed or zero-terminated strings, and binary representations of numbers (which you inadvertently did in your original code).
That is probably a bad way to do this. Like Mr. Universe was saying in the comments those arrays have all those additional blanks in them that have no data. I would change the case 2 code to something more like the following:
//#include <iomanip> for the stream formatting used when printing to the file
case 2:
{
//Open file
std::ifstream BinaryOpen("employee.txt", std::ios::in /*| std::ios::out*/ | std::ios::binary);
//Check if file is open
if(BinaryOpen.is_open())
{
//Read file
char eol[10];
while(BinaryOpen.good())
{
BinaryOpen >> favoriteEmployees[numberOfEmployees].firstName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].lastName;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hourlyWage;
BinaryOpen >> favoriteEmployees[numberOfEmployees].hoursWorked;
BinaryOpen >> eol;
numberOfEmployees++;
}
//Close file
BinaryOpen.close();
//Write to binary file
std::ofstream BinaryWrite("employee.dat", std::ios::out | std::ios::binary);
//Check if file opened
if(BinaryWrite.is_open())
{
for (int i = 0; i < numberOfEmployees; i++)
{
BinaryWrite << favoriteEmployees[i].firstName << " ";
BinaryWrite << favoriteEmployees[i].lastName << " ";
BinaryWrite << setiosflags(std::ios::fixed) << std::setprecision(2) << favoriteEmployees[i].hourlyWage << " ";
BinaryWrite << setiosflags(std::ios::fixed) << std::setprecision(2) << favoriteEmployees[i].hoursWorked << std::endl;
}
//Close file
BinaryWrite.close();
}
else
std::cout << "\nWrite file did not open! " << std::endl;
}
else
std::cout << "\nFile did not open! " << std::endl;
}
break;
As in my comment above. I have whipped up a quick example which will give you an idea of how to do this.
void SaveString(fstream& file_stream, string output)
{
// Note that any good string class will have an implicit conversion to char*
if (output.size() == 0)
return;
file_stream << (unsigned char)output.size();
for (unsigned char i=0; i<output.size(); i++)
file_stream << output[i];
// DONE (in theory)
}
Then all you need to do for the get is get 1 unsigned char at the start of your strings and then use that number in a for loop to getting chars and adding them to the string your loading into.