I am trying to manipulate an array with functions while switching between standard cin, cout and ifstream,ostream.
Specifically, I have an array of books and I have some basic functions like search title, publisher, price, etc. I also have 2 functions called "login" and "logout" to open a file and redirect bookList's istream and ostream to that outputfile when login, as well as close it and return back to istream, ostream when logout.
void bookList(istream& in, ostream& out)
{
//ask for command from istream in
//command selection loop
}
int load(ofstream& out, book booklist[], int size)
{
//load list of books from input file
}
void logon(ofstream& out, string filename)
{
out.open(filename.c_str());
}
void logoff(ofstream& out, string filename)
{
out.close();
}
// some other functions
I also need to print out notification to the user (either onscreen when logged off or on file when logged on) whenever a function is called.
My tried to put ifstream& as a parameter in each functions, but they only print out to text file not on screen (because its just ifstream, not istream), but doing it the other way won't work.
My question is that is there method that can make function logon redirect istream of bookList to ifstream to the outputfile and vice versa for logoff? Rather than a "is-file-open" condition.
This may not be directly what your looking for but can be modified.
/// this buffer will be used to switch output
void IO_Switch(streambuf* buffer);
int main(){
streambuf *buffer
ofstream fout;
fout.open("filename.txt");
// below you call cout.rdbuf() which directs stream to cout
IO_Switch(cout.rdbuf());
cout << "This is coming to the console";
// below you call fout.rdbuf());
IO_Switch(fout.rdbuf());
cout << "I used cout here, but the stream is redirected to fout ("filename.txt")
return 0;
}
void IO_Switch(streambuf* buffer){
cout.rdbuf(buffer);
}
Related
This was a question from a coding challenge and I couldn't figure out the way to do it -
Implement encode() and decode() for a simple wire protocol per the prototypes below:
void encode ( const std::string& inputFilename, std::ostream& out );
void decode ( std::istream& in, const std:string& outputFilename );
Lets say there are several files and each contains a single message. As it already says from the prototype, encode must read single specified file from disk and place message in the ostream.
Decode must read single encoded message from istream and place it in the specified file. The contents of the two corresponding files must be identical.
It is easy if I could read the file in the encode method and place the data in a buffer and send them to another file in the decode method, but that is not the question. How do I read data from std::istream without someone actually typing the data on the console (like std::cin)?
Thank you in advance for your time and would love to see responses for this!
istream is a parent class for ifstream (input file stream) and istringstream (input string stream), so you can pass as a input parameter ifstream or istringstream. Do not need to use cin.
The same applies to out parameter, you can provide object of the ofstream or ostringstream. This is well know mechanism in C++ to abstract what particular type of stream you deal with.
I wrote a piece of code that works with the prototypes given in the question. I am sure there could be more ways of doing it but I thought I would share this.
class fileIO
{
private:
std::string inBuf;
public:
std::stringstream testbuf;
void encode(const std::string& inputFilename, std::ostream& out);
void decode ( std::istream& in, const std::string& outputFilename);
};
void fileIO::encode(const std::string& inputFilename, std::ostream& out)
{
//read from the input file and stream it to ostream
ifstream infile(inputFilename);
while(infile.good()){
getline(infile, inBuf);
out << inBuf;
}
cout << "Value stored in outBuf: " << inBuf << endl;
infile.close();
}
void fileIO::decode(std::istream& in, const std::string& outputFilename)
{
//read from istream and output it to a file
string val;
ofstream ofile(outputFilename);
in >> val;
cout<< "Read the istream contents: " << val << endl;
ofile << val;
ofile.close();
}
int main( int argc, char ** argv )
{
fileIO File;
string inputFile;
cout << "Enter input File Name: "<< endl;
cin >> inputFile;
File.encode(inputFile, File.testbuf);
File.decode(File.testbuf, inputFile);
return 0;
}
I am passing "a stringstream" to both encode and decode since istream and ostream are the parent class of stringstream. In this solution, the value from the input file is stored in the stringstream and gets passed on to decode where the value from the same stringstream gets written to output file.
I have to write a "logon" and a "logoff" function which redirect the current iostream from a function to a fstream and back.
To be more specific, I have:
void console (istream& in, ostream& out)
{
//take command from user through console
//default input/ output stream is in/out
}
void logon (ostream& out, string filename)
{
ofstream fileout;
fileout.open(filename);
//assign this fstream fileout to ostream& out
}
void logoff (ostream& out)
{
// take current ofstream fileout
fileout.close();
// return the stream back to out
}
The program should work like this:
User enter some commands: Output to console
User enter logon filename command: create a file and redirect output to that file
User enter some commands: Output to file
User enter logoff: Close file, redirect output back to console
I know that ofstream is a part of ostream but don't know how to manipulate between the two.
Please help, any input is appreciated.
You could also use a std::string as an intermediary:
void consoleIn (std::istream& in, std::string& strInput)
{
in >> strInput;
}
void logon (std::ostream& out, std::string filename, std::string const& MyText)
{
std::ofstream fileout;
fileout.open(filename);
fileout << MyText;
}
And btw try to use std:: to specify standard objects.
Can you use a string stream as an intermediary?
stringstream ss;
while ofstream has data
ofstream >> ss
ostream << ss
....
Just an idea, not sure how practical this would be
If I have a simple function that prints to standard output maybe something like an integer or lets say a string like "Flipy flops", then is there a way to call the same function but instead of printing to standard output it prints the string "Flipy flops" to a file stream? (provided of course I've opened the file and all that stuff).
Yes just give it an ostream& parameter
void my_function(...)
{
cout << ...
}
becomes
void my_function(ostream& out, ...)
{
out << ...
}
Using fstream works just like cin and cout.
void SomeMethod( )
{
ofstream myFile( "myFile.txt" );
myFile << FlipyFlops( );
myFile.close( );
}
char* FlipyFlops( )
{
return "flipy flops"; // or "flippy floppies", whichever you prefer
}
ofstream is for output to a file and ifstream is for reading from a file.
Below is the basic structure code for my super market billing and stock editing program
class:
class Admin
{
public:
admin();
private:
int Pid;
char name[20];
double quant;
double price;
double disc;
double net_price;
friend istream &read(istream&, Admin&);
friend ostream &show(ostream&, const Admin);
};
istream &read(istream&, Admin&);
ostream &show(ostream&, const Admin);
definition of friend functions:
istream &read(istream &is, Admin &commodity)
{
double dis;
fflush(stdin);
is>>commodity.Pid;
is.getline(commodity.name,30);
is>>commodity.quant
>>commodity.price
>>commodity.disc;
dis=grs_pr*(commodity.disc/100);
commodity.net_price=grs_pr-dis;
return is;
}
ostream &show(ostream &os, const Admin thing)
{
os << thing.name <<" " << thing.quant <<" "
<< thing.price <<" " << thing.disc <<" "
<< thing.net_price << endl;
return os;
}
Main function:
int main()
{
admin item;
while(read(cin,item)
{
ofstream file;
file.open("Stock.dat",ios::binary | ios::app);
file.write(reinterpret_cast<const char*>(&item),sizeof(Admin));
}
ifstream readFile("Stock.dat",ios::in|ios::binary);
while(!readFile.eof())
{
readFile.read(reinterpret_cast<char*> (&item),sizeof(Admin));
Admin readedItem;
read(readFile,readedItem); /*i have used read and show function to watch the values that are read by readFile but every time show function output some five exponential values like 5.23689e-301*/
show(cout,readedItem);
}
return 0;
}
Please tell me what is wrong in above code and what should i do to correct it,
my motive is to read from the file created and to alter or edit the data of the item that is to be selected by mentioning the product ID by the user, please help me how to attain this functionality.
you shouldn't implement a naiive serialization yourself. Use a library.
See i.e. answers 1, 2+comments, 3, 4
Also, don't put logic of data manipulation (i.e. commodity.net_price=grs_pr-dis;) in your data serialization
Assuming I'm understanding right then your read and show loop should be
for (;;)
{
readFile.read(reinterpret_cast<char*> (&item),sizeof(Admin));
if (readFile.eof())
break;
show(cout,item);
}
For some reason you were reading twice, first into a variable called item and then into another variable called readItem. You only need to read once. Also while (!readFile.eof()) is wrong because you must test for end of file after you read not before.
I'm working on a program, that needs to load data from a text file upon starting and save data to THE SAME text file upon exit. I have the load working, and i have the save working, but for some reason I cant seem to have them both work within the same program.
This doesnt work...
ifstream loadfile("test.txt");
ofstream savefile("test.txt");
void load()
{
string name;
while(!loadfile.eof())
{
getline(loadfile,name);
cout<<"name " << name<<"\n";
}
}
void save(User &name)
{
savefile << name.getName() << endl;
}
Neither does this...
fstream file("test.txt");
void load()
{
string name;
while(! file.eof())
{
getline(file,name);
cout<<"name " << name<<"\n";
}
}
void save(User &name)
{
file << name.getName() << endl;
}
The thing is, I can save a list of names, which works fine... but as soon as i start the program, all the names from the list delete from the text file.
Also, I know that getline() gets the data from the text file as a string type, but how would i convert that to something like an int.
Thanks
Your files are being opened globally and never closed. Try:
void load()
{
ifstream loadfile("test.txt");
string name;
while(!loadfile.eof())
{
getline(loadfile,name);
cout<<"name " << name<<"\n";
}
}
void save(User &name)
{
ofstream savefile("test.txt");
savefile << name.getName() << endl;
}
ofstream savefile("test.txt");
is equivalent to:
ofstream savefile;
savefile.open("test.txt", ios::out|ios::trunc);
That is, you're truncating the file as you open it. So, move the initialization of savefile to happen after you're done with your load call (I'd suggest doing it as late as possible, because if you crash after that initialization and before you're done saving, the save file is corrupted -- normally one writes to a different file and only does the rename at the very end when everything is safe on disk).
In your first sample, you may be running afoul of OS file locking, preventing you from opening the same file for both read and write. Remember to always check for failure when opening a file.
In the second sample, you don't rewind the file pointer. Use seekg to reset the stream pointer before trying to read. Keep in mind that although there's a seperate seekg and seekp, in practice they may refer to the same pointer, so it's always best to seek before switching between read and write.
void load(){
ifstream loadfile("test.txt");
string name;
while(!loadfile.eof())
{
getline(loadfile,name);
cout<<"name " << name<<"\n";
}
loadfile.close(); // Call close() to free up resources again
}
void save(User &name)
{
ofstream savefile("test.txt");
savefile << name.getName() << endl;
savefile.close(); // Call close() to free up resources again
}
From Cplusplus I/O:
"Once this member function is called, the stream object can be used to open another file, and the file is available again to be opened by other processes."