Should ofstream throw exception when folder name is input? - c++

I want to generate file through ofstream, here are the codes.
void testOfstream(string filename){
ofstream ofs(filename, ofstream::out | ofstream::trunc | ofstream::binary);
char body[] = { 'a', 'b', 'c' };
ofs.write(body, sizeof(body)/sizeof(char));
ofs.close();
}
If the parameter filename is C:\\MyProject\\CodeTest2010\\CodeTest2010\\test.txt, the test.txt file is created successfully.
If the parameter filename is C:\\MyProject\\CodeTest2010\\CodeTest2010\\, or C:\\MyProject\\CodeTest2010\\CodeTest2010, nothing is changed in the folder CodeTest2010. I think it should throw exception to warning that the input file name is invalid.
My question is why it keeps silence instead of throwing exception, when the input file is folder not a filename?
According to this, I do not find any information about the folder name is input into ofstream.

IOStreams by default do not throw exceptions. Instead they delegate error indication to a bitmask type representing certain stream errors. The inability to open a file is classified as a recoverable error and therefore it sets std::ios_base::failtbit in its stream state. You can enable exceptions by specifying this bit in the parameters of the exceptions() method:
ofs.exceptions(std::ios_base::failbit);

Actually if you click through to the description of the constructor you'll see that:
If the file cannot be opened, the stream's failbit flag is set.
The default behaviour of iostreams is precisely this: failed operations do not throw exceptions but can be detected by checking the stream status bits. You can arrange for the stream to throw exceptions on failed operations using the ios::exceptions function although this doesn't apply to the constructor (since you have to construct the stream before you can call that function).

Related

How could I make my own file extention that works on a raspberry pi from C++?

How could I make my own file extention that works on a raspberry pi from C++?
I would like to make a file extention that keeps information for a custom OS for mobile devices such as phones, and tablets. what would the proper way to code an extention for this? information as in names, DOB, maybe their contacts?, and basically anything on the phone that id need to be stored permanantly. how would I do that?
File extensions don't really mean anything, it's just a part of the the file's name. It helps tell the operating system to what program to run with the given file. So making a file extension is quite simple, you just write your data to a file. Here is a great example of doing it in C++
After you have your binary you can read back just as easily, I'll quote a few lines from this site
A file stream object can be opened in one of two ways. First, you can supply a file name along with an i/o mode parameter to the constructor when declaring an object:
ifstream myFile ("data.bin", ios::in | ios::binary);
Alternatively, after a file stream object has been declared, you can call its open method:
ofstream myFile;
...
myFile.open ("data2.bin", ios::out | ios::binary);
Either approach will work with an ifstream, an ofstream, or an fstream object.
Normally, when manipulating text files, one omits the second parameter (the i/o mode parameter). However, in order to manipulate binary files, you should always specify the i/o mode, including ios::binary as one of the mode flags. For read/write access to a file, use an fstream:
fstream myFile;
myFile.open ("data3.bin", ios::in | ios::out | ios::binary);
To read from an fstream or ifstream object, use the read method. This method takes two parameters:
istream& read(char*, int);
The read member function extracts a given number of bytes from the given stream, placing them into the memory pointed to by the first parameter. It is your responsibility to create and manage the memory where read will place its result, as well as to ensure that it is large enough to hold the number of bytes requested. The bytes that are read and not interpreted, the method does not assume anything about line endings, and the read method does not place a null terminator at the end of the bytes that are read in.
If an error occurs while reading (for example, if you read off the end of a file), the stream is placed in an error state. If that occurs, you can use the gcount method to find out the number of characters that were actually read, and use the clear method to reset the stream to a usable state. Once a stream goes into an error state, all future read operations will fail.
An example:
#include <fstream.h>
...
char buffer[100];
ifstream myFile ("data.bin", ios::in | ios::binary);
myFile.read (buffer, 100);
if (!myFile) {
// An error occurred!
// myFile.gcount() returns the number of bytes read.
// calling myFile.clear() will reset the stream state
// so it is usable again.
}
...
if (!myFile.read (buffer, 100)) {
// Same effect as above
}

How should I manage ::std::cout after changing file descriptor 1 to refer to a different file?

I would like to do dup2(fd, 1); close(fd); and have ::std::cout write to the new fd 1. How do I can reset the state of ::std::cout so nothing goes funny? For example, is flushing beforehand sufficient? Or is there more to do than that?
I'm also curious about the same thing with ::std::cin.
Is there a standard mechanism for resetting these if you change out the file descriptors they're using underneath them?
To be clear, my goal here is basically to redirect my own input and output someplace else. I want to not have the process inadvertently burping up something on its parent's stdout or attempting to consume anything from its parent's stdin. And I never want to touch my parent's stdin or stdout ever again. I want to forget they ever existed.
And I most especially do not want to inadvertently ever send output to the same device my parent is using on a different file descriptor.
My goal is to have cin and cout lead to completely different places than they did when the process started, and to never ever touch in any way the places where they used to lead. Ever!
Option 1: set stdin & stdout
According to cppreference.com:
By default, all eight standard C++ streams are synchronized with their respective C streams.
And as long as you didn't explicitly called sync_with_stdio(false), they'll stay that way. What does it mean? The following:
In practice, this means that the synchronized C++ streams are unbuffered, and each I/O operation on a C++ stream is immediately applied to the corresponding C stream's buffer. This makes it possible to freely mix C++ and C I/O.
So, flush()-ing your cin & cout before dup()-ing them should be enough, since they should be in a consistent state.
If you wish to work with files for example, you could use:
if (freopen("input.txt", "r", stdin) == NULL) {
// Handle error, errno is set to indicate error
}
if (freopen("output.txt", "w", stdout) == NULL) {
// Handle error, errno is set to indicate error
}
Note 1: Setting the global extern FILE * stdin or stdout won't work because it simply changes a single instance of a pointer to the relevant FILE struct of the os. Any module that copied this pointer at any moment prior to this change will continue using the old FILE. A specific example is libc++'s implementation for cout, which copies FILE * stdout to a private member during the object's init. freopen on the other hand changes the internal FILE structure of the OS to use the newly opened file, affecting anyone who has a FILE * to it.
Note 2: When using dup() flavors (rather than freopen()), we are changing the underlying fd, rather than the FILE*. The freopen() method does more than that. From POSIX:
The freopen() function shall first attempt to flush the stream associated with stream as if by a call to fflush(stream). Failure to flush the stream successfully shall be ignored. If pathname is not a null pointer, freopen() shall close any file descriptor associated with stream. Failure to close the file descriptor successfully shall be ignored. The error and end-of-file indicators for the stream shall be cleared.
dup()-ing might work, but, it might be tricky, since it won't affect other properties of the FILE*, including: Character width, Buffering state, The buffer, I/O, Binary/text mode indicator, End-of-file status indicator, Error status indicator, File position indicator & (After C++17) Reentrant lock used to prevent data races.
When possible, I suggest using freopen. Otherwise, you could follow the steps described by yourself (fflush(), clearerr()). Skipping fclose() will be wise, since we won't be able to reopen the same internal FILE by any of the API methods.
Option 2: set cin's & cout's rdbuf()
The other way around, just like some comments proposed, is replacing cin's and cout's underlying buffer using rdbuf().
What are your options here?
File streams: Open ifstream & ofstream and use them:
std::ifstream fin("input.txt");
if (!fin) {
// Handle error
}
cin.rdbuf(fin.rdbuf());
std::ofstream fout("output.txt");
if (!fout) {
// Handle error
}
cout.rdbuf(fout.rdbuf());
Network streams: Use boost's boost::asio::ip::tcp::iostream (It's derived from std::streambuf and thus will work):
boost::asio::ip::tcp::iostream stream("www.boost.org", "http");
if (!stream) {
// Handle error
}
cin.rdbuf(stream.rdbuf());
cout.rdbuf(stream.rdbuf());
// GET request example
cout << "GET /LICENSE_1_0.txt HTTP/1.0\r\n";
cout << "Host: www.boost.org\r\n";
cout << "Accept: */*\r\n";
cout << "Connection: close\r\n\r\n";
cout.flush();
std::string response;
std::getline(cin, response);
Custom streams: Use your own custom wrapper for std::streambuf. See an example here.
You may create (or use an existing) library for a socket_streambuf class and associate this to std::cout/std::cin:
socket_streambuf<char> buffer{ "127.0.0.1:8888" }; // will call socket(), connect() or throw on failure
std::cout.rdbuf(&buffer); // re-direct cout to the network connection
std::cout << "Hello, World!\n"; // may call send() on basic_streambuf::overflow()
This way, you wouldn't have to bother about manipulating the state of the (global) C-stream buffers.

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.

Failing to read file loaded with ifstream

void bot_manager_item::create_games()
{
games.clear();
std::ifstream paths_in("C:\\Users\\bill hank\\Documents\\bot_plugins\\directory_listing.txt", std::ios::in);
while (paths_in.good())
{
send_message("The path was good.");
char q[5000];
paths_in.getline(q, 5000);
send_message(q);
games.push_back(qanda(q));
}
paths_in.close();
}
The file I'm loading exists, what else might be wrong? paths_in.good keeps failing.
Edit: I figured it out. Wow am I annoyed by the answer to this. Basically Windows lets you say whether you want to show file extensions or not. This windows installation is set to say that the extension shouldn't be shown. So when I'm checking the file again and again I'm seeing: directory.txt and thinking that this means that everything is fine with the directory when in reality the filename was directory.txt.txt
If paths_in.good() keeps failing then it means that some of the stream error flags are set (badbit, eofbit or failbit).
eofbit - end of file was reached
badbit - error with the stream buffer such as memory shortage or an exception inside the stream buffer is cast
failbit - some other error beside eof was reached
In order to find out what happened, you need to check which errorbit is set first, and then find out more about the specific error, and what can cause it.
Out of curiosity, does this code output the contents of the file correctly? If this code works, then the problem is something else. If this code doesn't work, then that likely means that the file either isn't where you specified, or you don't have read permissions on it.
void bot_manager_item::create_games() {
std::ifstream paths_in("C:\\Users\\bill hank\\Documents\\bot_plugins\\directory_listing.txt");
char q[5000];
while (paths_in.getline(q, 5000)) {
std::cout << q << std::endl;
}
}
This code does a few minor things differently.
std::ios::in doesn't need to be explicitly specified for std::ifstream.
it doesn't use is_good, while that should be fine, you can just treat the std::ifstream as a bool which will be true when it is in a good state.
getline() returns a reference to the stream it operated on, so you can just put that whole line in the condition.
cosmetic, but no need to explicitly close the ifstream if it is about to go out of scope.