How to write string stream to ofstream? - c++

I am trying to write a stringstream into a file but it not working.
int main() {
std::stringstream stream;
stream << "Hello world";
cout << stream.rdbuf()<<endl;//prints fine
std::ofstream p{ "hi.txt" };
p << stream.rdbuf();//nothing is writtten
p.close();
std::ifstream ip{ "hi.txt" };
std::string s;
ip >> s;
cout << s;//nothing printed
p.close();
return 0;
}
This answer here follows the same process. But it's not working in my case.

Internally, the stringstream maintain a read pointer/offset into its data buffer. When you read something from the stream, it reads from the current offset and then increments it.
So, cout << stream.rdbuf() reads the entire stream's data, leaving the read pointer/offset at the end of the stream. Thus, there is nothing left for p << stream.rdbuf() to read afterwards. In order to do that, you have to seek the read pointer/offset back to the beginning of the steam, eg:
cout << stream.rdbuf() << endl;
stream.clear(); // resets the error state, particularly eofbit
stream.seekg(0);
p << stream.rdbuf();

The C++ file streams use input and output pointers to keep track of it's data buffer. When you write something it is written from the position where the current write pointer is or we can say the write pointer offset is added and then the data is simply written, after which the write pointer is incremented by that much value
The stream.rdbuf() function reads all the data in the current file and leaves the read pointer at the end of the file so when we run the same function again there is nothing to read
This can Simply be solved by using stream.seekg(0)
cout << stream.rdbuf() << endl;
stream.seekg(0); //This puts the pointer at the beginning of the file
p << stream.rdbuf(); //Should work'

Related

How to read back what I just wrote to a file?

I've been trying to write a program to open a file in both read and write mode:
#include <fstream>
#include <iostream>
using namespace std;
int main(){
fstream obj;
obj.open("hello.txt",ios::in|ios::out);
if (!obj){
cout << "File not opened" <<endl;
return 1;
}
obj << "Hi How are you" ;
char c;
while (!obj.eof()){
obj.get(c);
cout << c;
}
obj.close();
return 0;
}
When I compile this program on Visual Studio Code on Windows, though the text "Hi how are you" is printed in the file, the contents of the file are not printed on my screen. Can someone tell me what might be the problem?
Resetting the position indicator with seekp to 0 helps, because both output and input indicators are set to the end of file after write operation (you can read them with tellp tellg).
obj << "Hi How are you" ;
obj.seekp(0);
char c;
while (!obj.eof()){
obj.get(c);
cout << c;
}
Considering avoiding using obj.eof(), you can e.g. read your file line by line:
std::string line;
std::getline(obj, line);
std::cout << line << std::endl;
or in the loop:
while (std::getline(obj, line)) // here std::basic_ios<CharT,Traits>::operator bool is used to check if operation succeeded
{
std::cout << line << std::endl;
}
You got two problems there: buffering and seek position.
Buffering:
When you write the text with obj << "Hi How are you, you just write it into the buffer and the text gets written into the file after flushing the buffer. You can adjust which buffer type you want to use. The easiest way is to write std::endl after your text if you use line buffering.
A better explaination is already here
Seek Position:
You are reading from the last position in your file. You have to manually change the read position to the first character in the file, then you are done.

Weird behavior with ifstreams and rdbuf()

I've noticed that using .rdbuf() on an ifstream seems to change it somehow. The following code should show the problem.
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
ifstream ifs("Sample.csv");
cout << "Reading buffer: " << endl;
cout << ifs.rdbuf(); // Outputs buffer as expected
cout << "Reading buffer again: " << endl;
cout << ifs.rdbuf(); // Returns nothing
return 0;
}
The reason this is bothering me is that I'm currently trying to copy the contents of one text file into another using ofstream ofs; ofs << ifs.rdbuf(). This works fine but makes reading from ifs using getline(ifs, str) fail, effectively "breaking" the stream.
This isn't particularly "weird"; it's the same stream behaviour you see every day. rdbuf isn't like std::stringstream::str() and it isn't magic — it's a pointer to the buffer, that your cout is then reading from just as you would read from the original stream yourself:
std::stringstream ss("1");
int x;
if (ss >> x)
cout << x;
if (ss >> x) // doesn't work a second time; "1" is already extracted
cout << x;
As your stream is a file stream, you can seek it back to the beginning to start from scratch (which will inherently do the same to its underlying buffer).
ifs.rdbuf() returns a pointer to the ifs's corresponding stream buffer object. Sending it to std::cout via << overload pulls information from the stream until the end of the buffer is reached (eof). Calling .rdbuf() again returns "nothing" because there's nothing to read at the end of the buffer. The buffer seek position be explicitly reset to zero by calling ifs.seekg (0);.

fstream using formatted data

i am new to this site , and this my first question !
i have a question about fstream function .
fstream f("new.dat",ios::out|ios::in);
fstream is for both input and output , so when we use it like this , and there is a new.dat file before it will output and input both . but it is strange , when i do that , it will output data correctly , but it is unable to input .
i found out if you close it , and reopen it , it will input . why it is like that??
int main()
{
fstream writeFile("newFile.dat", ios::out|ios::in);
char i[3];
char u[3]="HI";
if (!writeFile)
{
cerr << "error" << endl;
}
writeFile << u <<endl;
writeFile >> i;
cout << i << endl;
}
this is my full code , and result is an empty line.
The fstream object has a position in its output file, and since you opened it just for output and input without any position or writing modifiers, that position is at the end of the file. When you output i to the file, writeFile writes i to the file, and then moves its position past i so when you ask it to write more, you don't overwrite i.
You can reset the position to the start of the file with a call to writeFile.seekg(0), which places that internal position at the 0 position in the file (at the start).
If you're curious about stream manipulation, I'd suggest a look at cppreference.com and specifically its documentation on c++'s input and output libraries here.
Couple things going on here:
You can't open a file for reading if it doesn't exist, this includes a file you want to read and write. No file, no open.
Once you manage to open a file, the stream keeps track of where it is in the file. As you read or write, obviously the location moves.
There is only one location marker in the stream, so you can read to where you want to write, then write. Unfortunately this means any further reading will pick up after the write. If that's not what you want, get and store the current location (with tellg) before writing, and seek (with seekg) to the stored location after writing.
This has some problems such as what if the block of data you wish to insert is longer or shorter than the block of data you want to overwrite? The simple solution to this problem is read into buffer, edit buffer, write buffer back to file.
When you open a file and start writing into it, you overwrite whatever was in the file. If you want to add to a file, open with ios::app. This sets the stream's location to the end of the file. I am unaware of any sort of insert that pushes existing data along as you write in new data.
Some simple file handling example code
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main()
{
fstream f1("filename", ios::out);
if (f1.is_open())
{
if (f1 << "Hi")
{
cout << "wrote"<<endl;
}
f1.close();
}
fstream f2("filename", ios::out|ios::app);
if (f2.is_open())
{
if (f2 << " there!")
{
cout << "appended"<<endl;
}
f2.close();
}
fstream f3("filename", ios::in);
if (f3.is_open())
{
cout << f3.rdbuf()<< endl;
f3.close();
}
fstream f4("filename", ios::in|ios::out);
if (f4.is_open())
{
f4.seekg(3);
if (f4 << "Fred!")
{
cout << "overwrote"<<endl;
}
f4.close();
}
fstream f5("filename", ios::in);
if (f5.is_open())
{
cout << f5.rdbuf()<< endl;
f5.close();
}
// note the extra ! on the end left over from Hi there! I do not know how
// to get rid of this. I have always just done stuff like this to get around it.
fstream f6("filename", ios::in);
stringstream s1;
string token;
f6 >> token;
s1 << token << " Tim!";
f6.close();
fstream f7("filename", ios::out);
f7 << s1.rdbuf();
f7.close();
// and then moved temp over filename.
fstream f8("filename", ios::in);
cout << f8.rdbuf()<< endl;
f8.close();
}

overwriting data in a .txt file c++

I have a functions overwrites data on an existing file, however it isn't working properly here is my code:
void printList(entry* my_node)
{
ofstream output;
output.open("output.txt");
std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
if(my_node == NULL) return;
else {
string x=my_node->forename;
output<<x<<endl;
output<<my_node->surname<<endl;
output<<my_node->email<<endl;
output<<my_node->number<<endl;
std::cout<<"forename: "<<my_node->forename<<std::endl;
std::cout<<"surname: "<<my_node->surname<<std::endl;
std::cout<<"email: "<<my_node->email<<std::endl;
std::cout<<"Phone Number: "<<my_node->number<<std::endl;
printList(my_node->next);
output.close();
}
}
when i do this it clears the file and don't write anything to it ...i have also tried to first clear the file and then write to it
output.clear();
output.close();
output.open("output.txt",ios ::out|ios::app);
std::streambuf *coutbuf = std::cout.rdbuf();
//save old buf
///and then the rest but it didn't work as well
Any help please????
You call printList recursively with each next value until you reach the end of the list, which calls printlist(NULL). Then the output file is truncated again for the last time. This is the reason why the file is empty.
To write the whole list to the file, use a loop and inside the loop write each element, e.g.
while (my_node != NULL) {
output << my_node->forename << endl;
output << my_node->surname << endl;
output << my_node->email << endl;
output << my_node->number << endl;
/* ... */
my_node = my_node->next;
}
output.close();
You open and therefore overwrite the new file every time you reach printList, even in the case where my_node is null. If that is not your intention, then move
ofstream output;
output.open("output.txt");
into the body of the if statement. Or if you would like all nodes content in the same file, move it out of the traversal.
Also note that ofstreams contructor takes arguments, so you can write
ofstream output("output.txt");

why ostream's put pointer is modified even if i did not use ostream object

I have the below code in my program. IoFile.out has few lines.
int main()
{
ifstream inFile("Iofile.out", ios::in|ios::out);
ostream outStream(inFile.rdbuf());
cout << "tellp outStream " << outStream.tellp() << endl; // tellp outStream 0
cout << "tellg inFile " << inFile.tellg() << endl; // tellg inFile 0
cout << inFile.rdbuf(); // Print whole file
cout << "tellp outStream " << outStream.tellp() << endl; // tellp outStream 21
cout << "tellg inFile " << inFile.tellg() << endl; // tellg inFile 21
return 0;
}
The outputs of tellp and tellg are as shown in the comments.
My query is when I write the file content to cout I expect only the read pointer(i.e. tellg) of the streambuf to move to end of the file. But in this case I see that put pointer of outStream is also moved to end of file. Why is this ? Why printing the file to cout causing the put pointer of outStream to change ?
You cannot open an ifstream for writing. If you want both read & write access, use fstream.
You print the whole file, right?
You use a streambuffer pointer in the ostream constructor.
Then you print the data (this moves the pointer) (the ostream have a reference)
And get the pointer position (after you move it)
Your string have how many chars? (21?)
You moved the pointer when you printed the rdbuf().
I think its because inside it uses a arithmetic over its pointer