tags:

views:

591

answers:

3

I'm trying to use the ofstream class to write some stuff to a file, but all that happens is that the file gets created, and then nothing. I have some simply code here:

#include <iostream>
#include <fstream>

#include <cstring>
#include <cerrno>

#include <time.h>

using namespace std;

int main(int argc, char* argv[])
{
 ofstream file;
 file.open("test.txt");
 if (!file) {
  cout << strerror(errno) << endl;
 } else {
  cout << "All is well!" << endl;
 }

 for (int i = 0; i < 10; i++) {
  file << i << "\t" << time(NULL) << endl;
 }

 file.flush();
 file.close();
 return 0;
}

When I create a console application, everything works fine, so I'm afraid this code is not completely representative. However, I am using code like this in a much larger project that - to be honest - I don't fully understand (Neurostim). I'm supposed to write some class that is compiled to a dll which can be loaded by Neurostim.

When the code is run, "test.txt" is created and then "No error!" is printed, as this is apparently the output from strerror. Obviously this is wrong however. The application runs perfectly otherwise, and is not phased by the fact that I'm trying to write to a corrupted stream. It just doesn't do it. It seems to me like there is no problem with permissions, because the file is in fact created.

Does anyone have any ideas what kind of things might cause this odd behavior? (I'm on WinXP Pro SP3 and use Visual C++ 2008 Express Edition)

Thanks!

+1  A: 
    ofstream file;
    file.open("test.txt");

Just a nit: you can combine that into a single line. ofstream file("test.txt");

    if (file) {
            cout << strerror(errno) << endl;
    } else {
            cout << "All is well!" << endl;
    }

Your test is backwards. If file is true, it's open and ready for writing.

Also, I wouldn't count on strerror() working correctly on Windows. Most Windows APIs don't use errno to signal errors. If your failure is happening outside the C/C++ run-time library, this may not tell you anything interesting.

Warren Young
Thank you for your comments. The first thing is intentional, because in the real application `file` is a class attribute, so it has been declared in the header file and I can only open something later. I fixed the backwards check, it was actually correct in my real code. I actually have no idea what strerror() does but I saw it somewhere in a related problem (without a solution) and thought I'd use it to possibly give more information.
Jordi
I'd say you should make your test program reliably reproduce the error and try again then. As for strerror(), that's most at home on Unixy systems, where *every* error from the OS and RTL is signaled with errno. On Windows, you want to be looking at things like GetLastError().
Warren Young
A: 

UPDATE Thinking more about this, failing to open a file via fstreams is not guaranteed to set errno. It's possible that errno ends up set on some platforms (espeically if those platforms implement fstream operations with FILE* or file descriptors, or some other library that sets errno) but that is not guaranteed. The official way to check for failure is via exceptions, std::io_state or helper methods on std::fstream (like fail or bad). Unfortunately you can't get as much information out of std::streams as you can from errno.

You've got the if statement wrong. operator void* returns NULL (a.k.a. false) if the file is not writable. It returns non-zero (a.k.a. true) if the file is writeable. So you want:

if (!file) {
        cout << strerror(errno) << endl;
} else {
        cout << "All is well!" << endl;
}

Or:

if (!file.good()) {
        cout << strerror(errno) << endl;
} else {
        cout << "All is well!" << endl;
}
Max Lybbert
Yes, thank you, I got it backwards in my question, but not in my actual code. I fixed it now, but the problem still stands.
Jordi
+2  A: 

Just a thought :- in your real code are you re-using your stream object?

If so, you need to ensure that you call clear() on the stream before re-using the object otherwise, if there was a previous error state, it won't work. As I recall, not calling clear() on such a stream would result in an empty file that couldn't be written to, as you describe in your question.

markh44