I am struggling with a programming assignment in my C++ class. The assignment involves creating a random access file to store inventory for a hardware store. I can create, read and write to the file just fine. I have a function which opens the file or creates a new one if it does not exist. This function then returns the open file as std::fstream. I am trying to pass that open file to another function which prints out the contents of the file to the console. When I call the print function the first time it works just fine. However, when I return to the main menu and try and call the print function again, it prints out nothing from the file.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include "HardwareData.h"
void printMenu();
unsigned short int getMenuChoice();
std::string getFileName();
std::fstream openFile(const std::string& fileName);
std::fstream newFile(const std::string& filename);
void printHeader();
void printAllRecords(std::fstream& file);
void newRecord(std::fstream& file);
unsigned int getRecordNum(const std::string& prompt);
bool recordIsBlank(std::fstream& file, unsigned int recordNum);
int main() {
unsigned short int menuChoice{0};
std::string filename;
std::fstream file;
while(menuChoice != 6){
printMenu();
menuChoice = getMenuChoice();
switch(menuChoice){
case 1:
filename = getFileName();
file = openFile(filename);
break;
case 2:
printAllRecords(file);
break;
case 3:
newRecord(file);
break;
case 4:
break;
case 5:
break;
default:
break;
}
}
return(0);
}
std::string getFileName(){
std::string filename;
std::cout << "Enter a filename:";
std::cin >> filename;
return filename;
}
std::fstream openFile(const std::string& filename){
std::fstream file{filename, std::ios::in | std::ios::out | std::ios::binary};
if(!file){
std::cout << "File could not be opened." << std::endl;
std::cout << "Creating new file." << std::endl;
file = newFile(filename);
std::cout << "Successfully created " << filename << std::endl;
}
else{
std::cout << filename << " opened successfully" << std::endl;
}
return file;
}
std::fstream newFile(const std::string& filename){
std::ofstream file{filename, std::ios::out | std::ios::binary};
if(!file){
std::cerr << "File could not be created." << std::endl;
exit(EXIT_FAILURE);
}
HardwareData emptyRecord;
for(int i=0; i<100; i++){
file.write(reinterpret_cast<const char*>(&emptyRecord), sizeof(HardwareData));
}
file.close();
return openFile(filename);
}
void printHeader(){
std::cout << "Record# Tool Name Quantity Cost \n";
std::cout << "==================================================\n";
}
void printAllRecords(std::fstream& file){
file.seekg(0);
HardwareData record;
file.read(reinterpret_cast<char*>(&record), sizeof(HardwareData));
printHeader();
while(!file.eof()){
if(record.getRecordNum() != 0){
record.printRecord();
}
file.read(reinterpret_cast<char*>(&record), sizeof(HardwareData));
}
}
I was expecting to pass the file by reference and still be able to use that reference again on another function call. I am not getting any errors
Related
I am wondering how to make a lambda in C++ for this function and the type has to be void
void setIO(string s){
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
}
You can specify the type like so:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
const string FILE_NAME = "test.txt";
auto f = [](string const &name) -> void {
ofstream file;
file.open(name);
file << "junk\n" << "junk2" << endl;;
file.close();
};
f(FILE_NAME);
ifstream inputFile(FILE_NAME);
if (inputFile.is_open()) {
cout << "File is open." << endl;
string line;
while (getline(inputFile, line))
cout << line << '\n';
cout << flush;
inputFile.close();
} else
cerr << "Error opening file." << endl;
return EXIT_SUCCESS;
}
However, lambda functions can deduce the return type, so you can leave out -> void.
auto f = [](string const &name) {
ofstream file;
file.open(name);
file << "junk\n" << "junk2" << endl;;
file.close();
};
The equivalent way to create a lambda would be:
auto f = [](string s) -> void {
//freopen((s+".in").c_str(),"r",stdin);
//freopen((s+".out").c_str(),"w",stdout);
std::cout<<"inside lambda"<<std::endl;
//some other code here
};
Now you can use/call this as:
f("passing some string");
While working on this project for my younger cousin, I encountered many difficulties. I was wondering if someone could help me use char to output complete sentences (or help me fix these bugs.) I'm a relatively new programmer (about 8 months). Here's my code/ what I have attempted. Most of the bugs cause the program to freeze once a sentence is imputed, or the files not responding when opened.
#include<iostream>
#include<fstream>
#include<cctype>
#include<iomanip>
class legoset
{
char setcatname[25];
char name[50];
char legoinclude[25];
char legotype[25];
public:
void create_category();
void show_category() const;
void modify();
void report() const;
int retacno() const;
};
void legoset::create_category()
{
std::cout << "Please enter a category name : \n";
std::cin >> setcatname;
//std::cin.getline(setcatname, 25);
std::cout << "Please enter your username! \n";
std::cin >> name;
std::cin.ignore();
std::cin.getline(name, 50);
std::cout << name << " , is it a vehicle or building (V/B)?\n";
std::cin >> legotype;
legotype[25] = toupper(legotype[25]);
std::cin.getline(legotype, 25);
std::cout << "\n Please enter the name of the lego set. \n";
std::cin >> legoinclude;
//std::cin.getline(legoinclude, 25);
std::cout << "\n\n Category Created Successfully!!!";
return;
}
void legoset::show_category() const
{
std::cout << "Category : \n" << setcatname;
std::cout << "Username Of Holder \n: " << name;
std::cout << " Lego type (B/V) : " << legotype;
std::cout << " Lego set (with details) : " << legoinclude;
return;
}
void legoset::modify()
{
std::cout << "Category : \n" << setcatname[25];
std::cout << "\nModify Holder's name : ";
std::cin.ignore();
std::cin.getline(name, 50);
std::cout << "\nModify A Building or vehicle class ( B/V ) : ";
std::cin >> legotype[25];
legotype[25] = toupper(legotype[25]);
std::cout << "\nModify Lego set (with details) : ";
std::cin >> legoinclude[25];
}
void legoset::report() const
{
std::cout << setcatname[25] << std::setw(10) << " " << name << std::setw(10) << " " << legotype[25] << std::setw(6) << legoinclude[25] << std::endl;
}
int legoset::retacno() const
{
return setcatname[25];
}
void write_legoset(); //function to write record in binary file
void display_sp(int); //function to display account details given by user
void modify_set(int); //function to modify record of file
void delete_set(int); //function to delete record of file
void display_all(); //function to display all account details
void intro(); //introductory screen function
int main()
{
char choice;
int num;
intro();
do
{
system("cls");
std::cout << "\n\n\n\tMAIN MENU";
std::cout << "\n\n\t01. New Category";
std::cout << "\n\n\t02. ADD A NEW SET";
std::cout << "\n\n\t03. ALL USERS HOLDER LIST";
std::cout << "\n\n\t04. DELETE A CATEGORY";
std::cout << "\n\n\t05. MODIFY A CATEGORY";
std::cout << "\n\n\t06. EXIT";
std::cout << "\n\n\tSelect Your Option (1-6) ";
std::cin >> choice;
system("cls");
switch (choice)
{
case '1':
write_legoset();
break;
case '2':
std::cout << "\n\n\tEnter The category Name : "; std::cin >> num;
display_sp(num);
break;
case '3':
display_all();
break;
case '4':
std::cout << "\n\n\tEnter The Category Name : "; std::cin >> num;
delete_set(num);
break;
case '5':
std::cout << "\n\n\tEnter The Category Name : "; std::cin >> num;
modify_set(num);
break;
case '6':
std::cout << "\n\n\tThanks for using lego managemnt system!";
std::exit;
break;
default: std::cout << "\a";
}
std::cin.ignore();
std::cin.get();
} while (choice != '6');
return 0;
}
//***************************************************************
// function to write in file
//****************************************************************
void write_legoset()
{
legoset lego;
std::ofstream outFile;
outFile.open("legoset.dat", std::ios::binary | std::ios::app);
lego.create_category();
outFile.write(reinterpret_cast<char *> (&lego), sizeof(legoset));
outFile.close();
}
//***************************************************************
// function to read specific record from file
//****************************************************************
void display_sp(int n)
{
legoset lego;
bool flag = false;
std::ifstream inFile;
inFile.open("legoset.dat", std::ios::binary);
if (!inFile)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
std::cout << "\nLEGOSET DETAILS\n";
while (inFile.read(reinterpret_cast<char *> (&lego), sizeof(legoset)))
{
if (lego.retacno() == n)
{
lego.show_category();
flag = true;
}
}
inFile.close();
if (flag == false)
std::cout << "\n\nLego set does not exist in this file";
}
//***************************************************************
// function to modify record of file
//****************************************************************
void modify_set(int n)
{
bool found = false;
legoset lego;
std::fstream File;
File.open("legoset.dat", std::ios::binary | std::ios::in | std::ios::out);
if (!File)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
while (!File.eof() && found == false)
{
File.read(reinterpret_cast<char *> (&lego), sizeof(legoset));
if (lego.retacno() == n)
{
lego.show_category();
std::cout << "\n\nPlease Enter The New Details For This Category." << std::endl;
lego.modify();
int pos = (-1)*static_cast<int>(sizeof(legoset));
File.seekp(pos, std::ios::cur);
File.write(reinterpret_cast<char *> (&lego), sizeof(legoset));
std::cout << "\n\n\t Category Updated!";
found = true;
}
}
File.close();
if (found == false)
std::cout << "\n\n Category Not Found ";
}
//***************************************************************
// function to delete record of file
//****************************************************************
void delete_set(int n)
{
legoset lego;
std::ifstream inFile;
std::ofstream outFile;
inFile.open("legoset.dat", std::ios::binary);
if (!inFile)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
outFile.open("Temp.dat", std::ios::binary);
inFile.seekg(0, std::ios::beg);
while (inFile.read(reinterpret_cast<char *> (&lego), sizeof(legoset)))
{
if (lego.retacno() != n)
{
outFile.write(reinterpret_cast<char *> (&lego), sizeof(legoset));
}
}
inFile.close();
outFile.close();
remove("legoset.dat");
rename("Temp.dat", "legoset.dat");
std::cout << "\n\n\tCategory Deleted ..";
}
//***************************************************************
// function to display all accounts deposit list
//****************************************************************
void display_all()
{
legoset lego;
std::ifstream inFile;
inFile.open("legoset.dat", std::ios::binary);
if (!inFile)
{
std::cout << "File could not be open !! Press any Key...";
return;
}
std::cout << "\n\n\t\tUSER HOLDER LIST\n\n";
std::cout << "====================================================\n";
std::cout << "A/c no. NAME Type Balance\n";
std::cout << "====================================================\n";
while (inFile.read(reinterpret_cast<char *> (&lego), sizeof(legoset)))
{
lego.report();
}
inFile.close();
}
void intro()
{
std::cout << "\n\n\n\t LEGOSET";
std::cout << "\n\n\tMANAGEMENT";
std::cout << "\n\n\t SYSTEM";
std::cout << "\n\n\n\nMADE BY : Philippe Barry";
std::cin.get();
}
//***************************************************************
// END OF PROJECT
//***************************************************************
Note that array indices in C++ go from 0 to one less than the array size. Thus index 0 is the first element, index 1 is the second, etc. Thus if you declare a char array to be size 25, then accessing index 25 is past the end of the array and results in undefined behavior — your program may crash, freeze up, or literally anything else. Additionally, accessing index 24 would just give you the “null character” that comes after every string. If you’re sure that the input will be 24 characters long (and you shouldn’t be), then index 23 would contain the last character.
You really shouldn’t be using static-length char arrays in C++, anyway. Your current code, even if it worked most of the time with the char arrays, would fail when the input string was larger than the size of the array. Replace the types of all the char arrays with std::string, and the input function should work.
Furthermore, as Sam Varsavchik nicely put, don’t write an entire program at once. That makes it a nightmare to debug. Write your code in chunks — first write the input function, and a debug function that prints out the values of all the member variables. Debug that bit first, then go on to the rest.
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.
My goal is to take the text from "filename" that I have in my main directory, take the odd lines and send them over the filenameA, and the even lines to filenameB. From there, I want to splice them back into a new file. How can I create a while loop to do so?
// This program splits a file into two files from main directory
// and then splices the original file with a new name.
#include<iostream>
#include<fstream>
using namespace std;
void pause();
int main()
{
char filename[] = "Lab2Test.txt";
char filenameA[] = "LabTest-FA.txt";
char filenameB[] = "LabTest-FB.txt";
ifstream origin(filename);
ofstream fA(filenameA);
ofstream fB(filenameB);
if (! origin)
{
cout << filename << " could not be opened." << endl;
return -1;
}
string s;
int i=0;
while(getline(origin, s))
{
if(i % 2 == 1) //odd - write to LabTest-FA
fA << s << endl;
else
fB << s << endl;
i++;
}
}
void pause()
{
cin.sync();
cout << "Press any key to continue..." << endl;
cin.ignore();
}
First pick a book on C++ and learn a bit more about the language, you have lots of mistakes in the code.
Here is a working program, the best I can come up with.
// This program splits a file into two files from main directory
// and then splices the original file with a new name.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void pause()
{
cin.sync();
cout << "Press any key to continue..." << endl;
cin.ignore();
}
int main()
{
char filename[] = "Lab2Test.txt";
char filenameA[] = "LabTest-FA.txt";
char filenameB[] = "LabTest-FB.txt";
char filenew[] = "Lab2Test2.txt";
ifstream origin(filename);
fstream fA(filenameA, std::fstream::in | std::fstream::out | std::fstream::trunc);
fstream fB(filenameB, std::fstream::in | std::fstream::out | std::fstream::trunc);
ofstream fnew(filenew);
if (!origin)
{
cout << filename << " could not be opened." << endl;
return -1;
}
string s;
int i = 0;
while( getline(origin, s) )
{
if(i % 2 == 1) // odd - write to LabTest-FA
fA << s << endl;
else // even - write to LabTest-FB
fB << s << endl;
i++;
}
fA.flush(); // write to disk
fB.flush();
fA.seekg(0, ios::beg); // rewind the files to the beginning
fB.seekg(0, ios::beg);
string s1, s2;
while( getline(fB,s1) )
{
fnew << s1 << endl;
if(getline(fA,s2))
fnew << s2 << endl;
}
pause();
}
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.