C++ why is my file truncating when I restart my program? - c++

I'm trying to use this code to read from the file and store values in a vector. This works once and displays everything correctly.
void SongList::LoadSongsFromFile()
{
song temp;
string line;
ifstream myFile("SongListFile.txt");
while (getline(myFile, line)) {
myFile >> temp.title;
myFile >> temp.artist;
myFile >> temp.genre;
songs.push_back(temp);
}
}
I then want to append to the file, using the following:
void SongList::AddSong(song tmp)
{
cout << "Enter the title, artist then genre of the song, each on a new line.\n";
cin >> tmp.title;
cin >> tmp.artist;
cin >> tmp.genre;
songs.push_back(tmp);
ofstream myFile("SongListFile.txt");
myFile.open("SongListFile.txt", ios::app);
myFile << tmp.title << " " << tmp.artist << " " << tmp.genre;
cout << tmp.title << " by " << tmp.artist << " is now a part of the song library! ";
}
Everything works fine, but the file will wipe and have nothing in it once I finish the program, even if I have tried to append to the file. To be clear, I need the previous contents, and new lines that I have added to be there every time I reopen the program.

std::ofstream myFile("SongListFile.txt"); opens the file and truncates. You should use std::ofstream myFile("SongListFile.txt", std::ios::app);
Otherwise you can declare the myFile object with std::ofstream myFile; and then open a file using it and the append option: myFile.open("SongListFile.txt", std::ios::app);

replace
ofstream myFile("SongListFile.txt");
myFile.open("SongListFile.txt", ios::app);
with
ofstream myFile("SongListFile.txt",ios::app);
or
ofstream myFile;
myFile.open("SongListFile.txt", ios::app);
what happens in your code is that the ofstream myFile("SongListFile.txt") opens the file with default mode ios::out and then the attempt to open the file with myFile.open("SongListFile.txt", ios::app); in the next line fails because the file is already opened by the previous line making the ios::app ineffective for the file and thus every time you open the file using ofstream, the file gets truncated.

Actually ofstream constructor has 3 parameters: (const char *_Filename, ios_base::openmode _Mode = ios_base::out, int _Prot = (int)ios_base::_Openprot).
So the call std::ofstream myFile("SongListFile.txt"); is equavalent to
std::ofstream myFile("SongListFile.txt", std::ios::out);
Remark: std::ios::out == ios_base::out.
Other possible values for the second argument are:
std::ios::app
std::ios::trunc
Deeper in CRT code this parameter is first translated according to this:
std::ios::out --> std::ios::out
std::ios::trunc --> std::ios::trunc | std::ios::out
std::ios::app --> std::ios::app | std::ios::out
And a bit more deeper it is translated into good old fopen modes according to this:
std::ios::out --> "w"
std::ios::trunc | std::ios::out --> "w"
std::ios::app | std::ios::out --> "a"
fopen modes description from MSDN:
"w" - Opens an empty file for writing. If the given file exists, its contents are destroyed.
"a" - Opens for writing at the end of the file (appending) without removing the end-of-file (EOF) marker before new data is written to the file. Creates the file if it does not exist.
TL;DR:
std::ofstream myFile("SongListFile.txt"); - reset the file content.
std::ofstream myFile("SongListFile.txt", std::ios::out); - reset the file content.
std::ofstream myFile("SongListFile.txt", std::ios::trunc); - reset the file content.
std::ofstream myFile("SongListFile.txt", std::ios::app); - don't reset the file content.
First 3 variants are equivalent (for std::ofstream!).

Related

Why is there delay when I write on a file using c++?

I've tried to open a file, write something on it, read from the file and do the same process again but the output isn't what I expect, here's the code:
file.open("ciao.txt", std::ios::out);
file << "ciao";
file.close();
file.open("ciao.txt", std::ios::out | std::ios::in);
std::string str;
std::getline(file, str);
cout << str;
file.seekp(0);
file << "addio";
std::getline(file, str);
cout << str;
The expected oputput is "ciao addio", but it only gives me "ciao". I've tried to run it line after line, but the file is edited as soon as the program stops. Can someone help please? I couldn't find anything online ;-;
The problem is a combination of things.
Here you write ciao to the file, no problem - except it doesn't have a newline (\n).
file << "ciao";
Later, you read a line:
std::getline(file, str);
Had there been a \n in the file, EOF would not have been reached and the fstream would still be in good shape for accepting I/O. Now it's not however.
So, either file.clear() after the getline or add a newline to the first output:
file << "ciao\n";
You also need to file.seekg(0); before the last getline.
file.open("ciao.txt", std::ios::out);
file << "ciao";
file.close();
file.open("ciao.txt", std::ios::out | std::ios::in);
std::string str;
std::getline(file, str);
file.clear(); // add this
cout << str;
file.seekp(0);
file << "addio";
file.seekg(0); // add this
std::getline(file, str);
// I added > and < to make it clear what comes from the file:
cout << '>' << str << "<\n";
Output:
ciao>addio<

How to write data in binary form to a file using extract and insert operators in a stream?

Opening a file with fstream:
std::fstream fileStream(obj.path, std::ios::binary | std::ios::in | std::ios::out);
Next, I write data to the file:
fileStream << this->m_path;
fileStream << this->m_name;
fileStream << this->m_owner;
Opening the file, I see the data is not in binary form.
Is this only possible using function write?
fileStream.write((char*)&m_owner, sizeof(std::string));

Read from a file after have written to it with fstream - always empty

std::fstream file("filename", std::fstream::in | std::fstream::out | std::fstream::trunc);
if (file)
{
file << "Some text" << std::flush;
std::string buffer;
//file >> buffer;
std::getline(file, buffer);
std::cout << buffer;
}
I need to write to a file and read from it. After the run I can see the file with the text created, but with this code with both option how to read the buffer it is always empty. What am I doing wrong?
Use seekg(0) to set the position to start. When you wrote on the file it move the position to the end and for reading it you have to move to start.
std::fstream file("filename", std::fstream::in | std::fstream::out | std::fstream::trunc);
if (file)
{
file << "Some text" << std::flush;
std::string buffer;
//file >> buffer;
file.seekg(0);
std::getline(file, buffer);
std::cout << buffer;
}

Error copying text from one file to another c++ fstream

This is my code
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::fstream file;
file.open("text.txt", std::fstream::in | std::fstream::out |
std::fstream::app);
if(!file.is_open())
{
std::cout << "Could not open file(test.txt)" << std::endl;
} else {
file << "These are words \nThese words are meant to show up in the new file \n" <<
"This is a new Line \nWhen the new fstream is created, all of these lines should be read and it should all copy over";
std::string text;
file >> text;
std::cout << text << std::endl;
file.close();
std::fstream newFile;
newFile.open("text2.txt", std::fstream::in | std::fstream::out |
std::fstream::app);
if(newFile.is_open())
{
newFile << text;
}
}
}
I'm trying to copy the contents of text.txt to text2.txt but for some reason the text string always ends up empty. I've checked the files and text gets populated but text2 is empty. What's going wrong here?
When you append a string to an fstream, the input / output position is set to the end of the file. This means that when you next read from the file, all you will see is an empty string.
You can check what the current input position is by using:
file.tellg()
And set the input / output position to the start by using:
file.seekg(0)
The full reference for std::fstream is here.
You're trying to read from the end of the file. The position is set to the end of the last thing you wrote to the file, so, if you want to read what you wrote, you have to reset it:
file.seekg(0);
This will set the position for the input back to the start of the file. Note however that reading from the file the way you do now will simply get you 1 word (up to the first whitespace). If you want to read it all, perhaps you should look at something like: Read whole ASCII file into C++ std::string.

std::ofstream appending files

So I want to input something in a file but it doesn't seem to work. My code is this:
ofstream f("reservedTables.DAT");
cin >> table;
f.open("reservedTables.DAT", ios::out | ios::app);
f << table;
f.close();
What am I doing wrong? I write the number for the variable table but it doesn't appear in the file that I put it in
Quick walk through:
ofstream f("reservedTables.DAT");
Allocates stream and opens the file.
cin >> table;
Reads in input from user.
f.open("reservedTables.DAT", ios::out | ios::app);
Attempts to re-open the file. Will fail.
f << table;
Stream is in failed state after failed open and cannot be written.
f.close();
closes file.
Solution
Only open the file once and check for errors.
ofstream f("reservedTables.DAT", ios::app); // no need for ios::out.
// Implied by o in ofstream
cin >> table;
if (f.is_open()) // make sure file opened before writing
{
if (!f << table) // make sure file wrote
{
std::cerr << "Oh snap. Failed write".
}
f.close(); // may not be needed. f will automatically close when it
// goes out of scope
}
else
{
std::cerr << "Oh snap. Failed open".
}
That's because you are opening the file twice.
If you call open, you are actually calling rdbuf()->open(filename, mode | ios_base::out). Note that (ref):
If the associated file was already open, returns a null pointer right away.
Because a null pointer has been returned, it is assigned to the internal file buffer, and no file is opened anymore. This means that any attempts to write to it fail.
The constructor already opens the file if you specify a filename, so you don't need to call open:
std::ofstream f("reservedTables.DAT");
std::cin >> table;
f << table;
f.close();