Can I ask an iostream if it is writeable? - c++

In my code I am passed a reference to an iostream, that in this case is ultimately a file.
Is there any way to find out if, when it was opened, it was set to [in|out] not just [in]?

After looking at all the members of IOS, iostream, ostream, i did not see any way to retrieve the openmode flag used. I guess you'll have to try to write something to your reference and catch any error it throws. Or depending on how it is set, check the result of bad().

The openmode is passed down to std::streambuf, but there are no methods to retrieve it. The only way to know if the file is open for write operations is trying to write and checking for f.fail(), or optionally f.bad() (equivalent to f.rdstate() & std::fstream::badbit).

...kind of
if ( dynamic_cast<ostream*>( MyStreamPtr ) == 0 )
{
// Not for output...
}

Related

a quesition about c++ file I/O and fstream

I need to open a file and get the first character.If I open the file with ios::in,it will not create a file when the file doesn't exist.So when it was failed to open the file, i open the file with ios::out, it will creat a empty file, so i can input '0' to the file.
fstream passengerData;
passengerData.open("passenger.txt",ios::in);
if (!passengerData)
{
passengerData.open("passenger.txt",ios::out);
passengerData << '0' ;
passengerData.close();
}
When i run this in visual studio 2015,it can work well.But in visual c++ 6.0, it can only creat a empty file,the '0' is not input into the file.I want to know why the result is different and how to solve the problem.
I also want to know how the bitwise operator OR perform when i use ios::in|ios::out or ios::in|ios::out|ios::app.
From the documentation of fstream::open on cppreference it seems that it's only since C++11 that open also clear()s the flags on success, so maybe if you manually clear the flags before you call open the call will also succeed in VC++6:
fstream passengerData;
passengerData.open("passenger.txt",ios::in);
if (!passengerData)
{
passengerData.clear();
passengerData.open("passenger.txt",ios::out);
passengerData << '0' ;
passengerData.close();
}
Also, you need to check the state of passengerData after the second call to open as well.
The hunch that MicroVirus took on was right. I'd like to explain in detail why exactly nothing happened.
Basically, when passengerData.open("passenger.txt",ios::in); the failbit was set. Now you did retry with passengerData.open("passenger.txt",ios::out); which did succeed (sic!), although the error bits were not cleared (pre-c++11 behaviour), and made the subsequent operator<< do nothing.
I guess this was a flaw in the standard, and vc++6 is too old for c++11.
cppreference sources explaing the behaviour:
You use operator<<, which is a FormattedOutputFunction which says:
A FormattedOutputFunction is a stream output function that performs the following:
Constructs an object of type basic_ostream::sentry with automatic storage duration, which performs the following:
if eofbit or badbit are set on the output stream, sets the failbit as well [...]
So it checks whether the stream (passengerData) is operable. Now, interestingly enough, neither of eof or bad bits are set, so it seems like a wrong way, however the next step:
Checks the status of the sentry by calling sentry::operator bool(), which is equivalent to basic_ios::good.
Which takes you those eof-, fail-, and bad- bits. Those are iostates. In the failbit section you can find:
The failbit is set by the following standard library functions:
The constructors of std::basic_fstream, std::basic_ifstream, and std::basic_ofstream that takes a filename argument, if the file cannot be opened.
basic_fstream::open, basic_ifstream::open, and basic_ofstream::open if the file cannot be opened.
You can confirm this by checking the iostate bits after 2nd open:
fstream passengerData;
passengerData.open("passenger.txt",ios::in);
if (!passengerData)
{
passengerData.open("passenger.txt",ios::out);
if (passengerData.rdstate() & std::ios_base::fail) {
std::cout << "stream has failbit set\n";
}
passengerData << '0' ;
passengerData.close();
}

checking error while writing to a file

I have
ofstream myfile;
myfile.open(filename,ios::out | ios::app);
if(myfile.good()){ do smtg};
myfile.write(taskToWrite->buffer,taskToWrite->length);
Is there anyway to check if the write function doesn't work?
I'm checking before, with good(), but if I have an error while writing , how can I check it?
I couldn't understand what does the function returns.
The write function returns the stream itself. So in your case, it will return a reference to myfile. The stream types are convertible to bool to check its failure status. So you can simply use this:
if (myfile.write(taskToWrite->buffer,taskToWrite->length)) {
// Success
}
You could use std::ofstream::good() to check the state of the stream. If none of the error bits are set you can assume everything went well.

how do i legitimately change filename value of ofstream object?

I'm having troubles with ofstream , which is - when I change value of ofstream object like this
ofstream o_save;
/*code*/
o_save = ofstream(filename); //Problem is here
...the line above completely erase contents of file.
The question is how do I legitimately change filename value of ofstream object ?
P.S. I cant define it when I declare it, because I want it global and I'm not sure which save file I select.
The question is quite vague and contradictory, and the OP seems to have slept after asking the question. So I shall try to peek inside his head and try to elaborate what he wants.
For opening a file, there are many modes for that. Open it like this.
ofstream o_value ;
o_value.open("file.txt") ;
If you want to preserve the original contents of that file, use..
o_value.open("file.txt", ios::app) ;
If you want to close it later and open another one, close using...
o_value.close() ;
Chaning of file names is normally not allowed in case of ofstream. You can use rename from <cstdlib>. You can delete a file though using remove("file.txt") in <cstdio> .
What does it mean to "change the name" of an ofstream object?
The only "name" an ofstream object has is the name of the
variable. An ofstream object is a data stream. You can (on
some systems) change the name of the file it is associated with,
using rename, but somehow, I don't think this is what you want
either. You can also close the stream, and reopen it on another
file.
You cannot assign between iostream objects. If worse comes to
worse, you can declare the global object as a pointer, and
assign to it (using *o_save to write to it).
Finally, the standard says that when you open an ofstream, you
truncate the file, if one exists. If this is not what you want
to do, then you have to add some flags to the open mode. If you
add std::ios_base::app, for example, you will no longer
truncate the file, and all writes will be to the end of file
(atomically, if the system supports it). Alternatively (albeit
quite surprising), you could add std::ios::in to the flags;
this will fail if the file doesn't exist, but will allow writing
anywhere in the file. This is the only way to open a file for
writing if you want to be able to write anywhere in the file,
even if you don't want to read it.
The ofstream does not have some kind of an abstract name attribute, the name is just a parameter to some of its member functions, in that sense asking how to
change filename value of ofstream object
is meaningless.
In general you can rename files with std::rename from <cstdlib> or use Boost.Filesystem.

when would failbit be set while executing a getline function call in c++

when would getline in c++ fail?
I have a big snippet of code which I am unable to paste in its entirety for multifarious reasons. I am trying to read from a file , which I know exists and contains data, using getline in C++. But getline fails returning error 123-invalid name(output of getlasterror). I looked up the error code which baffles me even more.
I do error check while opening the file. So I am positive that I have the handle to the file.
Please bear with me for not pasting the code. I am new to c++ and especially in windows. Any suggestions or insights about getline would help. I am trying to read a file which is dumped by a compiler.
This is an extract from the code
ifstream inFile("C:\...\ash.txt",ios::in);
string singleLine;
getline(inFile,singleLine);
singleLine is empty ! I am doing something silly..pls point that out to me! appreciate it
IMPORTANT EDIT:
I checked for the ios members and found that fail bit is set. Why would the fail bit be set? the file does exist and also I was wondering if how windows exposes file extensions could cause a problem . That doesnt seem to the problem. What am i missing?
GetLastError only tells you about Win32 API calls, which std::getline is not.
Check the members of the iostream that failed, e.g. rdstate().
Calling ios::exceptions(eofbit | failbit | badbit) before getline and catching the resulting exception might or might not get you a more descriptive error message.
If the fail bit is set, it is probably because you didn't successfully open the file. Check whether ifFile.is_open() returns true; if not, then then probably indicates that the file is not open correctly. You might not have permissions, or you may need to escape the string properly, or the file may be locked.
You should also check if fail is set both before and after the call to getline. If it's before, that probably means that the file isn't open. If it's after, it could mean that the file is empty.
It may be the case that Windows is hiding the true file extension from you. The file name might actually be named ash.txt.txt, for example, if you have Explorer configured to hide file extensions. That might be worth investigating if the file isn't open.
Do you need to escape the backslashes in the file path?
It failed to open the file.
This is becuase you did not specify the correct path.
This is because you used the ancient windows convention of \ as a path separator.
Which also happens to be the escape character in C.
Which is why Windows lets you use / as a path separator (and has done for over a decade) because the use of '/' is so error prone.
Your path should be:
ifstream inFile("C:\\...\\ash.txt");
// Or my preference
ifstream inFile("C:/.../ash.txt");
Or even better use boost.
Getline IIRC is meant for c_strings and the string is the first argument, not the second.
http://www.cplusplus.com/reference/iostream/istream/getline/
You're attempting to use a normal string, which (I could be wrong) doesn't work with getline.

redirecting input in c++

i was told that to redirect from standard input to file i need to do the following:
static std::ifstream inF("inpur.txt");
std::cin.rdbuf(inF.rdbuf());
and every call to std::cin will be redirected to input.txt.
but my question is: do i need to open inF? and if i do, where do i need to do this?
You opened it by calling it with the string constructor.
That's the beauty. You already did so while declaring the object and passing the string to the explicit constructor of ifstream.
The file is opened in TEXT mode.
Refer this
Your code as-is fine. Do make a backup though of the original cin.rdbuf -- you may need to reset it in case of an error.