Writing to files safely in c++ - c++

Let's say you have a txt file, it currently holds content that's important. Currently the content is at such
"I like blue cats and yellow dogs."
but you want to update said content.
std::ofstream myFile;
myFile.open("file.txt");
myFile << "I like " << catColorStr << " cats and " << dogColorStr << " dogs.";
myFile.close();
But let's say for some reason your program crashes between line two and three or maybe the user's power cuts out or they use end process in windows task manager etc. Well you have just deleted the entire contents of file.txt. How do you go about accounting for this typically?
Is the typical way of dealing with this to open it as read only copy the contents to your program. Then copy that to a new tempfile or something. Then write to your actual file and if that succeeds deleting your tempfile else upon start you say your actual file = your temp file?

Typically, you create a new file, write to it, close it, then rename the new file to the old file.
std::ofstream myFile;
myFile.open("file.txt.new");
myFile << "I like " << catColorStr << " cats and " << dogColorStr << " dogs.";
myFile.close();
sys::filesystem::rename("file.txt.new", "file.txt");
// or POSIX rename or Windows or...
(Error checking omitted for brevity)
The rename operation atomically deletes the old file and gives the new file the old name. If somebody pulls the power cord in the middle of it, it's your operating system's problem, not yours. Modern OSes are quite good at dealing with it.

Related

Adding a new line to existing txt file in c++

As a tutorial I've been a question to add new line to an existing file with a list of items. i've tried numerous ways to add it. no luck yet
ofstream outdata;
ifstream indata;
indata.open("fruits.txt");
outdata.open("fruits.txt");
if(indata.is_open()){
std::string fruit;
std::cout << "enter a fruit to list "<<endl;
std::cin >> fruit;
outdata << "\n" << fruit << "\n" << endl;
indata.close();
outdata.close();
return 0;
}
This part of the code is supposed to ask the user to enter a value. Its supposed to be stored as new line without deleting the existing line. But here I'm. I've seen a few answers here. but can't find anything understandable.
When you open a file for writing its contents are immediately removed, if the file already exists.
outdata.open("fruits.txt");
You opened the same file for writing here. This is before your code tries to read anything from the same file (I don't actually see anything in your code that tries to read it, I presume you left that part out). And by the time you get to the file it's already empty and there's nothing to read any more from it.
You have three choices:
Read the entire contents of the file into your program, and only then open it for writing and write out the new contents.
Open a different file for writing. After finishing reading and writing both files, and closing them, rename the new file to the original file.
Open the file for appending:
outdata.open("fruits.txt", std::ios::app);
It's not necessary to open it for reading, this will add to the end of the file, instead of overwriting it.

Program opens file but is unable to write nor read from it

I was unable to access files in a program and drafted (mostly copied and pasted) a segment for testing doing so- just to troubleshoot.
fstream file;
file.open("thishere.txt");
if(file.is_open())
{
cout << "Managed to open file" << endl;
file << "Here's some info for muh file\n";
cout << "Attempted to give info to file, read: " << endl;
string line;
while ( getline (file,line) )
{
cout << line << '\n';
}
} else cout << "Failed to open file" << endl;
The program returns Managed to open file \n Attempted to give info to file, read: and stops there. There is text already in the file to read off of and it does not return anything. Also nothing new appears on the file.
So it manages to neither write down information on the file, nor read information from the file, even though it is supposedly open. When I delete the file from the directory my program says Failed to open file. I've heard of IDE's using the wrong directory so I manually used the EXE in the directory I wanted and got the same results. I have permissions to the file, and am running the EXE as administrator.
What am I missing?
I'm using Windows 8 if that's pertinent
EDIT:
I solved my own problem if anyone cares, it was only half the code. There was no file.close() so the file did not save. Kenny Orstroms answer also solved my problem of no text appearing. All good now!

How to open a separate program with C++ / OS X

How can I open a program (.exe or .app) using my C++ program?
Like iTunes, Safari, Pages.
For example;
If I wanted to manually write into a "example.txt", "example.docx" or "example.pages" file, how could I get that file to open the TextEdit, M Word or Pages programs/applications rather than write from inside the Terminal.
I'm not talking about fstream, as thats all I can find on the topic. I feel I've got that pretty down packed (basic example code below)
cout << "Enter File Name:\n" << endl;
cin >> fileName;
char a;
cin.get(a);
outStream.open(fileName.c_str());
cout << "\nWhat would you like to write?\n" << endl;
getline(cin, fileWrite);
cout << "\nWriting to " << fileName << endl;
outStream << fileWrite;
outStream.close();
While I want my program to be able to Read/Write in streams, I want to also be able to add an option of having the ACTUAL document open so you can MANUALLY Read or Write into it along with the programs edit features and whatnot without using the "system()" command (as I've read that it has too many risks depending on what you're choosing to open)
The correct approach to opening documents, URLs, or applications on OS X is to use the Launch Services API. (If you were using Cocoa, you would use NSWorkspace, which is built on top of Launch Services.) In particular, you can call LSOpenCFURLRef().

File write, without deleting old lines?

I currently have this to write to a file in my program. I have all the variables ready to put into the file I just have an issue.
void fileWrite(int score)
{
ofstream file;
file.open("MathGen.txt");
file << "The score was: " << score;
file.close();
}
So when this runs it creates the files and writes the score perfectly fine. But if I re-run the program and get a new score it will overwrite the old score. Is there any way to stop this from happening? I know in python you could use file write functions such as "a+". But that doesn't work here.
You should use append mode on your file in ofstream.open:
file.open("MathGen.txt", std::ofstream::app);
More info on this method is here

C++ - ofstream doesn't output to file until I close the program

I have the following code:
ofstream mOutFile.open(logPath, ios_base::app);
string lBuilder;
lBuilder.append("========================================================\n");
lBuilder.append("Date: ");
lBuilder.append(asctime(timeinfo));
lBuilder.append("\n");
lBuilder.append("Log Message:\n");
lBuilder.append(toLog);
lBuilder.append("\n");
lBuilder.append("========================================================\n\n");
int lSize = lBuilder.size();
char* lBuffer = new char[lSize];
int index = 0;
for each (char c in lBuilder)
lBuffer[index++] = c;
mOutFile.write(lBuffer, lSize);
mOutFile.flush();
Unfortunately, until I close the app (I assume that closing the ofstream would work as well) the output does not get written to the text file. I know I could probably close and reopen the stream and everything will "just work" but that seems like a silly and incorrect solution. What am I doing wrong here?
I have also tried the following variations based on other questions I have found here, but these solutions did not work:
mOutputFile << flush;
mOutputFile << endl;
Thanks in advance for any assistance on this.
edit Everything in this code is working visual c++, it builds and works fine except the file is not written to until the stream is closed, even if I force a flush. Also, I switched from using the << operator to the char * and .write () to see if anything behaved differently.
std::ofstream file(logPath, ios_base::app);
file << "========================================================\n"
<< "Date: " << asctime(timeinfo)
<< "\nLog Message:\n" << toLog
<< "\n========================================================\n\n"
<< std::flush;
//if you want to force it write to the file it will also flush when the the file object is destroyed
//file will close itself
This is not only easier to read but it will probably also be faster than your method + it is a more standard appraoch
I ended up just "making it work" by closing and reopening the stream after the write operation.
mOutputFile << "all of my text" << endl;
mOutputFile.close();
mOutputFile.open(mLogPath);
EDIT After trying out forcing the flush on a few other systems, it looks like something just isn't performing correctly on my development machine. Not good news but at least the above solution seems to work when programmatically flushing the ofstream fails. I am not sure of the implications of the above code though, so if anyone wants to chime in if there are implications of closing and reopening the stream like this.
You can perform the following steps to validate some assumptions:
1.) After flush(), the changes to the file should be visible to your application. Open the file as std::fstream instead of std::ofstream. After flushing, reset the file pointer to the beginning and read the contents of the file. Your newly written record should be there. If not, you probably have a memory corruption somewhere in your code.
2.) Open the same file in an std::ifstream after your call to flush(). Then read the contents of the file. Your newly written record should be there. If not, then there's probably another process interfering with your file.
If both works, then you may want to read up on "file locking" and "inter-process syncronization". The OS can (theoretically) take as much time as it wants to make file changes visible to other processes.