Error handling in std::ofstream while writing data - c++

I have a small program where i initialize a string and write to a file stream:
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
std::ofstream ofs(file.c_str());
string s="Hello how are you";
if(ofs)
ofs<<s;
if(!ofs)
{
cout<<"Writing to file failed"<<endl;
}
return 0;
}
My diskspace is very less, and the statement "ofs<" fails. So I know that this is an error logically.
The statement "if(!ofs)" does not encounter the above issue, hence I am unable to know why it failed.
Please tell me, by which other options I would be able to know that "ofs< has failed.
Thanks in advance.

In principle, if there is a write error, badbit should be set. The
error will only be set when the stream actually tries to write, however,
so because of buffering, it may be set on a later write than when the error occurs, or even after
close. And the bit is “sticky”, so once set, it will stay
set.
Given the above, the usual procedure is to just verify the status of the
output after close; when outputting to std::cout or std::cerr, after
the final flush. Something like:
std::ofstream f(...);
// all sorts of output (usually to the `std::ostream&` in a
// function).
f.close();
if ( ! f ) {
// Error handling. Most important, do _not_ return 0 from
// main, but EXIT_FAILUREl.
}
When outputting to std::cout, replace the f.close() with
std::cout.flush() (and of course, if ( ! std::cout )).
AND: this is standard procedure. A program which has a return code of 0
(or EXIT_SUCCESS) when there is a write error is incorrect.

I found a solution like
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
std::ofstream ofs(file.c_str());
string s="Hello how are you";
if(ofs)
ofs<<s;
if(ofs.bad()) //bad() function will check for badbit
{
cout<<"Writing to file failed"<<endl;
}
return 0;
}
You can also refer to the below links here and thereto check for the correctness.

Related

I can't get the ofstream function to work

Hello and sorry if the answer is clear to those out there. I am still fairly new to programming and ask for some guidance.
This function should write just one of the three string parameters it takes in to the txt file I have already generated. When I run the program the function seems to work fine and the cout statement shows the info is in the string and does get passes successfully. The issue is after running the program I go to check the txt file and find it is still blank.
I am using C++17 on visual studio professional 2015.
void AddNewMagicItem(const std::string & ItemKey,
const std::string & ItemDescription,
const std::string &filename)
{
const char* ItemKeyName = ItemKey.c_str();
const char* ItemDescriptionBody = ItemDescription.c_str();
const char* FileToAddItemTo = filename.c_str();
std::ofstream AddingItem(FileToAddItemTo);
std::ifstream FileCheck(FileToAddItemTo);
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
if (_access(FileToAddItemTo, 0) == 0)
{
if (FileCheck.is_open())
{
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
}
AddingItem.close(); // not sure these are necessary
FileCheck.close(); //not sure these are necessary
}
This should print out a message onto a .txt file when you pass a string into the ItemKey parameter.
Thank you very much for your help and again please forgive me as I am also new to stackoverflow and might have made some mistakes in formatting this question or not being clear enough.
ADD ON: Thank you everyone who has answered this question and for all your help. I appreciate the help and would like to personally thank you all for your help, comments, and input on this topic. May your code compile every time and may your code reviews always be commented.
As mentioned by previous commenters/answerers, your code can be simplified by letting the destructor of the ofstream object close the file for you, and by refraining from using the c_str() conversion function.
This code seems to do what you wanted, on GCC v8 at least:
#include <string>
#include <fstream>
#include <iostream>
void AddNewMagicItem(const std::string& ItemKey,
const std::string& ItemDescription,
const std::string& fileName)
{
std::ofstream AddingItem{fileName, std::ios::app};
if (AddingItem) { // if file successfully opened
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
else {
std::cerr << "Could not open file " << fileName << std::endl;
}
// implicit close of AddingItem file handle here
}
int main(int argc, char* argv[])
{
std::string outputFileName{"foobar.txt"};
std::string desc{"Description"};
// use implicit conversion of "key*" C strings to std::string objects:
AddNewMagicItem("key1", desc, outputFileName);
AddNewMagicItem("key2", desc, outputFileName);
AddNewMagicItem("key3", desc, outputFileName);
return 0;
}
Main Problem
std::ofstream AddingItem(FileToAddItemTo);
opened the file. Opening it again with
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
caused the stream to fail.
Solution
Move the open modes into the constructor (std::ofstream AddingItem(FileToAddItemTo, std::ios::app);) and remove the manual open.
Note that only the app open mode is needed. ofstream implies the out mode is already set.
Note: If the user does not have access to the file, the file cannot be opened. There is no need to test for this separately. I find testing for an open file followed by a call to perror or a similar target-specific call to provide details on the cause of the failure to be a useful feature.
Note that there are several different states the stream could be in and is_open is sort of off to the side. You want to check all of them to make sure an IO transaction succeeded. In this case the file is open, so if is_open is all you check, you miss the failbit. A common related bug when reading is only testing for EOF and winding up in a loop of failed reads that will never reach the end of the file (or reading past the end of the file by checking too soon).
AddingItem << ItemKey;
becomes
if (!(AddingItem << ItemKey))
{
//handle failure
}
Sometimes you will need better granularity to determine exactly what happened in order to properly handle the error. Check the state bits and possibly perror and target-specific
diagnostics as above.
Side Problem
Opening a file for simultaneous read and write with multiple fstreams is not recommended. The different streams will provide different buffered views of the same file resulting in instability.
Attempting to read and write the same file through a single ostream can be done, but it is exceptionally difficult to get right. The standard rule of thumb is read the file into memory and close the file, edit the memory, and the open the file, write the memory, close the file. Keep the in-memory copy of the file if possible so that you do not have to reread the file.
If you need to be certain a file was written correctly, write the file and then read it back, parse it, and verify that the information is correct. While verifying, do not allow the file to be written again. Don't try to multithread this.
Details
Here's a little example to show what went wrong and where.
#include <iostream>
#include <fstream>
int main()
{
std::ofstream AddingItem("test");
if (AddingItem.is_open()) // test file is open
{
std::cout << "open";
}
if (AddingItem) // test stream is writable
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
AddingItem.open("test", std::ios::app);
if (AddingItem.is_open())
{
std::cout << "open";
}
if (AddingItem)
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
}
Assuming the working directory is valid and the user has permissions to write to test, we will see that the program output is
open and writable
open and NOT writable
This shows that
std::ofstream AddingItem("test");
opened the file and that
AddingItem.open("test", std::ios::app);
left the file open, but put the stream in a non-writable error state to force you to deal with the potential logic error of trying to have two files open in the same stream at the same time. Basically it's saying, "I'm sorry Dave, I'm afraid I can't do that." without Undefined Behaviour or the full Hal 9000 bloodbath.
Unfortunately to get this message, you have to look at the correct error bits. In this case I looked at all of them with if (AddingItem).
As a complement of the already given question comments:
If you want to write data into a file, I do not understand why you have used a std::ifstream. Only std::ofstream is needed.
You can write data into a file this way:
const std::string file_path("../tmp_test/file_test.txt"); // path to the file
std::string content_to_write("Something\n"); // content to be written in the file
std::ofstream file_s(file_path, std::ios::app); // construct and open the ostream in appending mode
if(file_s) // if the stream is successfully open
{
file_s << content_to_write; // write data
file_s.close(); // close the file (or you can also let the file_s destructor do it for you at the end of the block)
}
else
std::cout << "Fail to open: " << file_path << std::endl; // write an error message
As you said being quite new to programming, I have explicitly commented each line to make it more understandable.
I hope it helps.
EDIT:
For more explanation, you tried to open the file 3 times (twice in writing mode and once in reading mode). This is the cause of your problems. You only need to open the file once in writing mode.
Morever, checking that the input stream is open will not tell you if the output stream is open too. Keep in mind that you open a file stream. If you want to check if it is properly open, you have to check it over the related object, not over another one.

fprintf() / std::cout doesn't print part of the string to stdout/stderr

I have this strange problem with stdout/stderr.
I want to apologize for not being able to put here the original code, it's too long / too many libraries dependent etc...
So please let me know if you ever encountered anything like it, or what may cause this issue without getting the original code, only the idea and examples of the simple things I tried to do:
I'm using g++ (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4) on RHEL 6.3
I couldn't isolate the problem for putting it here, I'll give code examples of what I did.
fprintf() / printf() / std::cout stops working after a while.
I'm using boost::asio::io_service with deadline_timer in order to call a my_print() function.
This my_print() function prints to screen every 1 second some information.
In order to print, I use alignments, like the following:
fprintf(stdout, "%*s\n", -printWidth, someEnumToStr[i]);
fprintf(stdout, "%s\n", aString);
fprintf(stdout, "%u\n", num);
While aString is a std::string. Sometimes I construct aString from std::ostringstream.
Sometimes I construct it with snprintf().
I have an std::map with information, exactly 16 elements inside the map. I iterate over it, and for each element I try to print data with the example of fprintf() above.
For an unknown reason, the line of element 16 isn't printed.
If I call the executable, and redirect stdout to a file (./a.out > aaa.txt) the line of element 16 is getting printed.
If I open a new FILE* and fprintf() to this file, again, everything is getting printed (all lines, including line of element 16)
Before using fprintf() I tried to use std::cout (and alignments with std::cout.width(printWidth) << std::left...), The same behavior happened, but when line 16 wasn't drawn, stdout got stuck (I mean, the program still worked, but nothing was printed to stdout never again. I had to call std::cout.clear() for it to work again). Since a point in the code, which I couldn't lay my hands on, std::cout.failbit and badbit were 1.
If I run the code with valgrind this behavior doesn't happen. valgrind doesn't say anything wrong.
If I run it with gdb it happens, but gdb doesn't say anything wrong.
If I run it in an IDE (clion) in debug mode, it doesn't happen.
If I run it in IDE, without debug, it happens.
I figure it depends on the printWidth I give for the alignment in fprintf() - When printWidth is bigger, it happens sooner (when it's smaller, line 16 is randomly getting printed).
Another important thing: it happens more frequently when there is more to print.
I tried to give std::cout a bigger buffer (not his default) and it didn't work.
I tried to buffer all of the output into a buffer (instead of printing each line), then to only fprintf() once. Same behavior happens.
I didn't find anywhere in the code I try to print a NULL pointer.
I print with \n every couple of fprintf()s, and do fflush() in the end of my_print()
Please let me know if you know anything.
Illustration:
deadline_timer..... every 1 sec... my_print()
boost::asio::io_service.run
my_print() {
for(std::map<>::iterator... begin, end, ++it....) {
fprintf()s....
}
}
Non printable characters may be breaking terminal.
fprintf(stdout,"%s", astdstring.cstr() );
Is how to print std::string
I use boost::asio, I have a callback to read from stdin. this read is nonblocking - happens with async_read_some().
The problem was stdin was turned to be nonblocking, and it also caused stdout to be nonblocking as well because they point to the same file description (explanation).
It caused the fprintf() calls to fail (returned -1 with errno 11) and not all of the output got printed out on the screen.
It has no relation to boost.
I succeeded isolating the problem, the following code creates this problem:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
using namespace std;
int main(int argc, char *argv[]) {
const int problem = 8000;
const int myBuffSize = 32000;
char *myBuff = new char[myBuffSize];
int myoffset = 0;
memset(myBuff, '-', myBuffSize);
int flags;
bool toogle = true;
bool running = true;
// Comment from here
if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0) {
printf("error fcntl()\n");
return 0;
}
if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) < 0) {
printf("error fcntl()\n");
return 0;
}
// Comment until here
while(running) {
toogle = toogle ? false : true;
if (toogle) {
snprintf(myBuff + problem, myBuffSize - problem, "fin\n\n");
} else {
snprintf(myBuff + problem, myBuffSize - problem, "end\n\n");
}
fprintf(stdout, "%s", myBuff);
sleep(1);
}
delete[] myBuff;
return 0;
}
If you'll comment the // Comment from here to // Comment untill here, it will print all of the output (fin and end will be printed).
One solution to this problem is to open another fd to the current tty using fopen(ttyname(STDOUT_FILENO), "w") and to print into it.
I believe another solution is to async_write() into screen.
The output might be stuck in a buffer, and not flushed before program termination.
Try adding exit(0) at the end of the program, and see if it helps.
http://www.cplusplus.com/reference/cstdlib/exit/
All C streams (open with functions in <cstdio>) are closed (and flushed, if buffered), and all files created with tmpfile are removed.

Cannot read text file in C++

I am stumped by this simple problem. I am reading a text file with C++:
std::ifstream stream;
stream.open(filename);
if (!stream)
cout << "Invalid stream" << endl;
And !stream is true but there seems to be nothing wrong with the text file. Under what circumstances can stream be false?
Note: is_open returns true
You have not provided enough information. Nevertheless, my psychic powers reveal:
filename is a relative path, and your current working directory is not what you think it is.
Inside your if clause, before printing via std::cout, add this:
perror(filename.c_str());
This code works for me:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
int main()
{
std::ifstream infilestream;
std::string line;
infilestream.open("test.txt");
while(infilestream)
{
std::getline(infilestream, line);
cout<<line<<"\n";
}
infilestream.close();
return(0);
}
chances are your file is inaccessible OR you might not have enough privileges to access the file.
Maybe its open somewhere else? Check if the path to the file is right.

Does anyone know why fstream crashes at this line?

This is the first time i ran into this problem so I have no idea how to fix it.
EDIT: Nevermind. Look like an off by one error in my constructor caused this to happen somehow
#include <iostream>
#include <fstream>
#include "graphm.h"
using namespace std;
int main() {
ifstream infile1("data31.txt");
for(;;){
GraphM G;
G.buildGraph(infile1);
if (infile1.eof())
break;
}
void GraphM::buildGraph(ifstream& infile){
int i = 0;
infile >> i; //it crashes here
}
my text file is just 1 line:
5
The problem might be related to the file not being open. You should always check whether a file has been successfully opened:
ifstream infile1("data31.txt");
if ( !infile1 )
{
// Failed to open data31.txt
return -1;
}
or you can use an explicit function instead of overloaded operator!
if ( infile1.fail() )
{
return -1;
}
What is the error that you get? Make sure that the file is open by checking the infile.is_open() function. you can find the sample code here:
http://www.cplusplus.com/reference/iostream/ifstream/is_open/
You can also check this thread:
Using C++ ifstream extraction operator>> to read formatted data from a file
It has a useful instructions for using ifstream.
Possible problems with the code:
1. Unopenable file/unopened file
2. Unopenable file/unopened file
3. Unopenable file/unopened file
4. Unopenable file/unopened file
How to get around this problem? Follow #MaximSkurydin's code.

When will ofstream::open fail?

I am trying out try, catch, throw statements in C++ for file handling, and I have written a dummy code to catch all errors. My question is in order to check if I have got these right, I need an error to occur. Now I can easily check infile.fail() by simply not creating a file of the required name in the directory. But how will I be able to check the same for outfile.fail() (outfile is ofstream where as infile is ifstream). In which case, will the value for outfile.fail() be true?
sample code [from comments on unapersson's answer, simplified to make issue clearer -zack]:
#include <fstream>
using std::ofstream;
int main()
{
ofstream outfile;
outfile.open("test.txt");
if (outfile.fail())
// do something......
else
// do something else.....
return 0;
}
The open(2) man page on Linux has about 30 conditions. Some intresting ones are:
If the file exists and you don't have permission to write it.
If the file doesn't exist, and you don't have permission (on the diretory) to create it.
If you don't have search permission on some parent directory.
If you pass in a bogus char* for the filename.
If, while opening a device file, you press CTRL-C.
If the kernel encountered too many symbolic links while resolving the name.
If you try to open a directory for writing.
If the pathname is too long.
If your process has too many files open already.
If the system has too many files open already.
If the pathname refers to a device file, and there is no such device in the system.
If the kernel has run out of memory.
If the filesystem is full.
If a component of the pathname is not a directory.
If the file is on a read-only filesystem.
If the file is an executable file which is currently being executed.
By default, and by design, C++ streams never throw exceptions on error. You should not try to write code that assumes they do, even though it is possible to get them to. Instead, in your application logic check every I/O operation for an error and deal with it, possibly throwing your own exception if that error cannot be dealt with at the specific place it occurs in your code.
The canonical way of testing streams and stream operations is not to test specific stream flags, unless you have to. Instead:
ifstream ifs( "foo.txt" );
if ( ifs ) {
// ifs is good
}
else {
// ifs is bad - deal with it
}
similarly for read operations:
int x;
while( cin >> x ) {
// do something with x
}
// at this point test the stream (if you must)
if ( cin.eof() ) {
// cool - what we expected
}
else {
// bad
}
To get ofstream::open to fail, you need to arrange for it to be impossible to create the named file. The easiest way to do this is to create a directory of the exact same name before running the program. Here's a nearly-complete demo program; arranging to reliably remove the test directory if and only if you created it, I leave as an exercise.
#include <iostream>
#include <fstream>
#include <sys/stat.h>
#include <cstring>
#include <cerrno>
using std::ofstream;
using std::strerror;
using std::cerr;
int main()
{
ofstream outfile;
// set up conditions so outfile.open will fail:
if (mkdir("test.txt", 0700)) {
cerr << "mkdir failed: " << strerror(errno) << '\n';
return 2;
}
outfile.open("test.txt");
if (outfile.fail()) {
cerr << "open failure as expected: " << strerror(errno) << '\n';
return 0;
} else {
cerr << "open success, not as expected\n";
return 1;
}
}
There is no good way to ensure that writing to an fstream fails. I would probably create a mock ostream that failed writes, if I needed to test that.