Writing stringstream contents into ofstream - c++

I'm currently using std::ofstream as follows:
std::ofstream outFile;
outFile.open(output_file);
Then I attempt to pass a std::stringstream object to outFile as follows:
GetHolesResults(..., std::ofstream &outFile){
float x = 1234;
std::stringstream ss;
ss << x << std::endl;
outFile << ss;
}
Now my outFile contains nothing but garbage: "0012E708" repeated all over.
In GetHolesResults I can write
outFile << "Foo" << std:endl;
and it will output correctly in outFile.
Any suggestion on what I'm doing wrong?

You can do this, which doesn't need to create the string. It makes the output stream read out the contents of the stream on the right side (usable with any streams).
outFile << ss.rdbuf();

If you are using std::ostringstream and wondering why nothing get written with ss.rdbuf() then use .str() function.
outFile << oStream.str();

When passing a stringstream rdbuf to a stream newlines are not translated. The input text can contain \n so find replace won't work. The old code wrote to an fstream and switching it to a stringstream losses the endl translation.

I'd rather write ss.str(); instead of ss.rdbuf(); (and use a stringstream).
If you use ss.rdbuf() the format-flags of outFile will be reset rendering your code non-reusable.
I.e., the caller of GetHolesResults(..., std::ofstream &outFile) might want to write something like this to display the result in a table:
outFile << std::setw(12) << GetHolesResults ...
...and wonder why the width is ignored.

Related

How to use string for .get using fstream?

I need to use string instead of char to write several characters at once.
I want the first cycle to take data from the file and the second cycle to go through the string cycle to \0
since in the future I want to receive 2 or 4 characters at a time.
Can I implement this to get .get working through string?
fstream fs("file.txt", fstream::in | fstream::out | ios::binary);
for (string i; fs.get(i);) {
cout << i;
}
istream::get with a c-string reads up to n characters, or a delimiter, default newline (very similar to istream::getline, but it leaves the delimiter in the stream, while getline consumes it).
To read fixed length blocks regardless there is istream::read, and istream::gcount says how much was actually read. Unfortunately neither have an overload for std::string specifically, the main downside being having to size (and thus initialize) a string first.
Putting them together you can get something like:
std::string buffer;
std::fstream is("file.txt", std::ios::in | std::ios::binary);
while (is)
{
buffer.resize(128); // Whatever size you want
is.read(buffer.data(), buffer.size()); // Read into buffer, note *does not null terminate* // C++17
//is.read(&buffer[0], buffer.size()); // Older C++
buffer.resize(is.gcount()); // Actual amount read. Might be less than requested, or even zero at the end or a read failure.
std::cout << "Read " << buffer.size() << " characters." << std::endl;
std::cout << buffer << std::endl;
}
For getline specifically, there is std::getline which handles std::string for you:
std::string buffer;
std::fstream is("file.txt", std::ios::in | std::ios::binary);
while (std::getline(is, buffer))
{
std::cout << "Line: " << buffer << std::endl;
}
Note that both get and getline can use some other delimiter, so it doesn't have to be "lines".

ifstream not working with variable parameter using C++11 and c_str() appended

Note: I am using the C++11 standard, so I don't see why this isn't working with or without c_str() appended.
I have the following code:
// open streams
ifstream in(input);
ofstream out(output);
// get which file to open
in.ignore(INT_MAX, ':'); // we don't need the beginning part
in.ignore(); // remove trailing whitespace
string fileLocation;
getline(in, fileLocation);
out << "Loading: " << fileLocation << endl;
cout << "Loading: " << fileLocation << endl;
// now that we know where the file is, load it:
ifstream file(fileLocation);
which reads from a file that looks vaguely like this
File: file.txt
(Subcommands below)
I know that I am pulling the correct filename because of the terminal output.
Anyway, I noticed that the stream wasn't opening properly, so I added this conditional to check:
if ( !file )
{
cout << "File wasn't loaded properly." << endl;
}
And sure enough, I see that message when running the program.
My question is this: how come, when I hard-code the file location, e.g. ifstream file("file.txt") it opens up no problem? How do I get this working properly?

edit: trouble checking if file is empty or not, what am I doing wrong?

Edit: changed my question to be more accurate of the situation
I'm trying to open up a text file (create it if it doesnt exist,open it if it doesnt). It is the same input file as output.
ofstream oFile("goalsFile.txt");
fstream iFile("goalsFile.txt");
string goalsText;
string tempBuffer;
//int fileLength = 0;
bool empty = false;
if (oFile.is_open())
{
if (iFile.is_open())
{
iFile >> tempBuffer;
iFile.seekg(0, iFile.end);
size_t fileLength = iFile.tellg();
iFile.seekg(0, iFile.beg);
if (fileLength == 0)
{
cout << "Set a new goal\n" << "Goal Name:"; //if I end debugging her the file ends up being empty
getline(cin, goalSet);
oFile << goalSet;
oFile << ";";
cout << endl;
cout << "Goal Cost:";
getline(cin, tempBuffer);
goalCost = stoi(tempBuffer);
oFile << goalCost;
cout << endl;
}
}
}
Couple of issues. For one, if the file exist and has text within it, it still goes into the if loop that would normally ask me to set a new goal. I can't seem to figure out what's happening here.
The problem is simply that you are using buffered IO streams. Despite the fact that they reference the same file underneath, they have completely separate buffers.
// open the file for writing and erase existing contents.
std::ostream out(filename);
// open the now empty file for reading.
std::istream in(filename);
// write to out's buffer
out << "hello";
At this point, "hello" may not have been written to disk, the only guarantee is that it's in the output buffer of out. To force it to be written to disk you could use
out << std::endl; // new line + flush
out << std::flush; // just a flush
that means that we've committed our output to disk, but the input buffer is still untouched at this point, and so the file still appears to be empty.
In order for your input file to see what you've written to the output file, you'd need to use sync.
#include <iostream>
#include <fstream>
#include <string>
static const char* filename = "testfile.txt";
int main()
{
std::string hello;
{
std::ofstream out(filename);
std::ifstream in(filename);
out << "hello\n";
in >> hello;
std::cout << "unsync'd read got '" << hello << "'\n";
}
{
std::ofstream out(filename);
std::ifstream in(filename);
out << "hello\n";
out << std::flush;
in.sync();
in >> hello;
std::cout << "sync'd read got '" << hello << "'\n";
}
}
The next problem you'll run into trying to do this with buffered streams is the need to clear() the eof bit on the input stream every time more data is written to the file...
Try Boost::FileSystem::is_empty which test if your file is empty. I read somewhere that using fstream's is not a good way to test empty files.

std::stringstream only supports one input at a time?

Since std::stringstream is a stzream, and according to the documention here, you can perform any operation a stream supports.
So I expected the following sample to work, but it seems it doesn't. I'm using MingW with gcc 4.8.3.
Variant A:
std::string s;
std::stringstream doc;
doc << "Test " << "String ";
doc << "AnotherString";
doc >> s;
std::cout << s << std::endl;
Variant B:
std::string s;
std::stringstream doc;
doc << "Test ";
doc << "AnotherString";
doc >> s;
std::cout << s << std::endl;
The output of this is only
Test
While I expected that it would concatenate the individual strings until I read from the stream back what I put there.
So what is the approperiate way to concatenate strings? Do I really have to read out each one individually and concatenate them manually, which seems quite awkward to me in C++.
It is putting each of the strings into doc, so that its content is:
Test String AnotherString
Then when you extract using doc >> s, it only reads up to the first whitespace. If you want to get the entire stream as a string, you can call str:
std::cout << doc.str() << std::endl;
It will only read one word till a white-space by using stream >> s. Besides #JosephMansfield's answer of using str(), alternatively you can use getline() (works perfectly if you the string doesn't contains new lines):
getline(doc, s);

Get the number of data entries in another file?

I need to know if you can easily get the number of data entries in another file and save that number in the original file. Need a program that will process the other file no matter how many entries are in it. Hope that makes any sense.
Your question is very poorly worded but I think you are looking for getline. This function can parse an input file based on the newline character (default behaviour) or based on a user provided delimiter:
int entryCount = 0;
std::string currentLine;
std::ifstream inFile( "in.txt" );
std::ofstream outFile;
if (inFile) // short for inFile.good())
{
while (std::getline( inFile, currentLine))
{
++entryCount;
// Do your processing
}
inFile.close();
outFile.open( "out.txt" );
outFile << "End of file. " << entryCount << " entries read." << std::endl;
outFile.close();
}
else
std::cout << "oops... error opening inFile" << std::endl;