Is this the way to create a new file?

  • Thread starter Thread starter yungman
  • Start date Start date
  • Tags Tags
    File
Click For Summary

Discussion Overview

The discussion revolves around the creation and management of files in C++ programming, specifically focusing on how to create a file only if it does not already exist, and how to write and read strings from files. Participants explore various methods and share code snippets to illustrate their points.

Discussion Character

  • Technical explanation
  • Exploratory
  • Debate/contested
  • Homework-related

Main Points Raised

  • One participant describes a method to check for file existence by attempting to open it in input mode and creating it in output mode if it fails.
  • Another participant suggests using ios::app to ensure that data is appended to the file without overwriting existing content.
  • There is a discussion about the failbit and goodbit flags in file streams, indicating whether a file operation succeeded or failed.
  • Some participants inquire about alternative methods for writing std::strings to files, expressing confusion over the use of the streaming operator and the limitations of getline with output streams.
  • One participant compares C++ file handling with VB.NET, mentioning a function that checks for file existence.
  • Concerns are raised about the behavior of input and output operations with std::string and c-strings, with participants sharing their experiences and observations.

Areas of Agreement / Disagreement

There is no clear consensus on the best method for file creation and management, as participants present various approaches and express differing opinions on the effectiveness and safety of these methods.

Contextual Notes

Participants note limitations in their understanding of C++ file handling, particularly regarding the differences between std::string and c-strings, and the behavior of input/output operations. There are also mentions of unresolved issues with specific code snippets and functions.

Who May Find This Useful

This discussion may be useful for C++ programmers looking to understand file handling, particularly those interested in creating files conditionally and managing string data in files.

yungman
Messages
5,741
Reaction score
291
I am writing a program that I need to create a file the FIRST time the program is run, but not create one every time I run the program and NOT touch the data in the file if the file already exist. I know if the file does not exist, ios::in will not create the file, just give an error message that the file does not exist:
C++:
fstream file;
file.open("demofile.dat", ios::in | ios::binary);//will give error if file does not exist.
Only open in "out" mode will create a new file if it does not exist:
C++:
fstream file;
file.open("demofile.dat", ios::out|ios::binary);//Will create file if it does not exist

This is what I have so far to first test whether the file exist by first open in ios::in mode. If it fails, then I know the file does not exist, then I create the file by open in ios:out mode. Will this destroy data if the file do exist but somehow failed to open:
C++:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{  fstream file;
   file.open("demofile.dat", ios::out|ios::in | ios::binary);//test for existence.
   if (file.fail())
   {
       count << " file does not exist.\n\n";
       file.open("demofile.dat", ios::out|ios::binary);//create file if it does not exist.
       file.close();
   }
   return 0;
}

Or is there a better way to test if the file exist, don't touch it. If it is the very first time running the program and the file is not created yet, then create the file. So after inputting the data, the next time, the file already exist and the program can just add and delete data and modify the file.

Thanks
 
Technology news on Phys.org
jedishrfu said:
It seems you are on the right track. Here's a similar example:

https://www.systutorials.com/how-to...ist-and-open-it-in-read-and-write-modes-in-c/
Thank you,

Looks like just putting ios::app so even if it accidentally write something, it will write to the next new element.

But I think since I just open in ios::out to create the file, then close it right away, nothing should happen to the file. Adding the ios::app is just insurance.

Thanks for your time.
 
yungman said:
If it is the very first time running the program and the file is not created yet, then create the file.
Many of the C++ routines such as open return a value or set a bit somewhere to indicate whether the operation succeeded or failed.

fstream:: open doesn't return a value, but it sets failbit if the open failed.
If the function fails to open a file, the failbit state flag is set for the stream (which may throw ios_base::failure if that state flag was registered using member exceptions).
See http://cplusplus.com/reference/fstream/basic_ifstream/open/

Your code could attempt to open a file, and then check to see if failbit is set. If so, you can assume that the file doesn't exist, at least in the directory where you're looking for it.
If goodbit is set, then it's safe to assume that the file exists.
 
Last edited:
  • Like
Likes   Reactions: yungman
I have been reviewing files AND spending time on line searching, I am looking for other ways to write std::strings to file other than using streaming operator <<. Is there a file.write() to write file that is not binary file? is there something like getline(file, St) where St is std::string?

I tried fstream outputFile; getline(outputFile, St). At least it did not give me a compile error. But it failed to write. If I use ofstream outputFile, it gave me an error.

The only way so far is using streaming operator << like outputFile << St; I just want to make sure I am not missing something.

Thanks
 
yungman said:
I have been reviewing files AND spending time on line searching, I am looking for other ways to write std::strings to file other than using streaming operator <<. Is there a file.write() to write file that is not binary file? is there something like getline(file, St) where St is std::string?
There is ostream::write -- see http://cplusplus.com/reference/ostream/ostream/write/
yungman said:
I tried fstream outputFile; getline(outputFile, St). At least it did not give me a compile error. But it failed to write. If I use ofstream outputFile, it gave me an error.
getline(outputFile, St) doesn't make any sense. You are using an input function, getline, on an output stream. At least I assume from the name you used, outputFile, that it is an output stream.
 
  • Like
Likes   Reactions: Vanadium 50
Mark44 said:
There is ostream::write -- see http://cplusplus.com/reference/ostream/ostream/write/
getline(outputFile, St) doesn't make any sense. You are using an input function, getline, on an output stream. At least I assume from the name you used, outputFile, that it is an output stream.
Thanks

I saw that post, That is for allocate memory of char. I have no issue with c-string, but std::string is different. the

C++:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>

using namespace std;

int main()
{   
    fstream outputFile;
    ifstream inputFile;
   
    string line;
    string writeLine = " This is a test. next line.";

    outputFile.open("emptyfile.txt", ios::out);
    outputFile.write(writeLine, sizeof(writeLine));//
//    getline(outputFile, writeLine);
    outputFile.close();

    inputFile.open("emptyfile.txt");
    getline(inputFile, line);
    count << " From getline(inputFile, line):  " << line << "\n\n";
    return 0;
}

I even look at this:http://www.cplusplus.com/forum/beginner/92758/
Inside, you can see this( I deleted the lines in between). Obviously it doesn't work. I tried it already as you see in line 18 that I blocked out already.
C++:
string text;
ofstream myfile;
myfile.open (file);
getline (myfile, text);

I did spend quite a bit of time searching with no luck.

Thanks
 
yungman said:
I am writing a program that I need to create a file the FIRST time the program is run, but not create one every time I run the program and NOT touch the data in the file if the file already exist.
I've long forgotten what's available in C/C++, but in VB.NET there is a function dir("full file path and name"), which will return the name of the file (without the path) if the file exists and a blank string otherwise, so to write a file only if it doesn't already exist, just do:

Code:
if dir(filename) = "" then
     write the file
end if
 
  • Like
Likes   Reactions: yungman
phinds said:
I've long forgotten what's available in C/C++, but in VB.NET there is a function dir("full file path and name"), which will return the name of the file (without the path) if the file exists and a blank string otherwise, so to write a file only if it doesn't already exist, just do:

Code:
if dir(filename) = "" then
     write the file
end if
Thanks
I definitely going to try that after I resolve the file write question.

Thanks
 
  • #10
The reason I want to actually spend the time on file read and write using different ways is because they are all different depending on whether it's std::string or c-string. I have not even get to the int and int array yet. I am glad we don't have std::int string!

It's strange that for string, inputFile >> St will ONLY read until the first space is reached. eg if "This is a test \n next" in the file, I can only read "This".

BUT....if I read to char cAr[], inputFile >> cAr will give me "This is a test", stop at '\n'; I could swear that it can only read "This", that we have to use inputFile.getline(cAr, sizeof(cAr)) to get the sentence. I kept changing the cAr to different sentences, Rebuild Solution and Clear Solution to make sure I was not seeing things.

That's why I redo every single situation and write it clearly in my notes. With my old brain, there is NO CHANCE I can remember all these details. I am stopping everything to get this complete even if I have to delay my schedule.
 
  • #11
Mark44 said:
At least I assume from the name you used, outputFile, that it is an output stream.

Why assume that? He uses "emptyfile" as a file with data in it.
 
  • #12
phinds said:
I've long forgotten what's available in C/C++, but in VB.NET there is a function dir("full file path and name"), which will return the name of the file (without the path) if the file exists and a blank string otherwise, so to write a file only if it doesn't already exist, just do:
Maybe it is just me, but checking for the existence of a file in one statement and then taking action on that file in the next creates a race condition. If we are alone on the machine, the sequence can work. But I am a paranoid sort -- I do not like assuming that we are alone on the machine. Somebody else may be creating and deleting files other than just us.

Back in my younger days using VAX/VMS the file system (RMS) had a primitive to deal with this -- a "create-if" flag on the open statement. If the file already existed, you got a file pointer to the existing file. If not, you got a file pointer to a new file. I think there was a status bit in the return code that could tell you which it was.
 
  • #13
Yeah, reasonable point. I'm accusomed to doing single-machine development w/ no one else working on it.
 
  • #14
yungman said:
I saw that post, That is for allocate memory of char.
My comment was about what you wrote in post #5; namely, getline(outputFile, St) . Here you are using an input function, getline, on an output stream. That's what doesn't make any sense. getline has to be used on a stream that has been opened for input, not output.

Regarding the code you posted in #7, here's a version that works. Note that I've changed many of your variable names to ones that are more reasonable.
C++:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstring>

using namespace std;

int main()
{
    fstream outFile, inFile;
    //ifstream inFile;

    string str;
    string testString = " This is a test. next line.";
    // int testStringLen = testString.length();

    outFile.open("Data.txt", ios::out);
    const char *Cstr = testString.c_str();
    // outFile.write(Cstr, testStringLen);
    outFile.write(Cstr, strlen(Cstr));
    outFile.close();

    inFile.open("Data.txt");
    getline(inFile, str);
    count << " From inFile:  " << str << "\n\n";
    return 0;
}
To use write, the first argument needs to be an array of type char or a const char pointer. In line 19, I'm using the c_str() function to convert the characters in testString (an STL string object) to a null-terminated array of characters (a C-string). The c_str() function was suggested in another thread as a way to extract the characters in a string object, to put them in a C-string.

The second argument of write is the number of characters (bytes) to write. This can be done in either of two ways:
  1. Use strlen() in the cstring.h header on the C-string. My code includes this header.
  2. Use the length() function on the string object.
In my code I did this both ways, but I have commented out the second way, above.

For the write function, it's tempting to do this:
C++:
outFile.write(Cstr, sizeof(Cstr));
But all this does is to write 4 characters of Cstr to the output stream. I leave it as an exercise for you to figure out why only 4 characters are written.

Other comments:
There was nothing wrong with your choices of outputFile and inputFile. In my version I used slightly shorter names that still convey what they're going to be used for.

The ifstream and ofstream classes inherit from the fstream class, so I have declared both inFile and outFile to be of type fstream , rather than have one stream object be of type fstream and another be of type ifstream. The C++ run time "knows" which type of stream each will be based on the parameters used when you open the streams.

As already mentioned, "emptyFile.txt" is not a good name for a file, since it is not likely to remain empty.
 
  • Like
Likes   Reactions: sysprog and yungman
  • #15
jbriggs444 said:
but checking for the existence of a file in one statement and then taking action on that file in the next creates a race condition.

True, but do you really think yungman's problem is that things just aren't complicated enough?

First, this problem is academic at the moment. We have a single user writing in his own directory through an IDE.

Second, he is a beginner. Everything can't be taught at once. He's trying to read from an output stream at the moment, for heaven's sake.
 
  • Like
Likes   Reactions: Mark44, phinds and jbriggs444
  • #16
Mark44 said:
But all this does is to write 4 characters of Cstr to the output stream. I leave it as an exercise for you to figure out why only 4 characters are written.

Four or 8?
 
  • #17
Mark44 said:
My comment was about what you wrote in post #5; namely, getline(outputFile, St) . Here you are using an input function, getline, on an output stream. That's what doesn't make any sense. getline has to be used on a stream that has been opened for input, not output.

Regarding the code you posted in #7, here's a version that works. Note that I've changed many of your variable names to ones that are more reasonable.
C++:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstring>

using namespace std;

int main()
{
    fstream outFile, inFile;
    //ifstream inFile;

    string str;
    string testString = " This is a test. next line.";
    // int testStringLen = testString.length();

    outFile.open("Data.txt", ios::out);
    const char *Cstr = testString.c_str();
    // outFile.write(Cstr, testStringLen);
    outFile.write(Cstr, strlen(Cstr));
    outFile.close();

    inFile.open("Data.txt");
    getline(inFile, str);
    count << " From inFile:  " << str << "\n\n";
    return 0;
}
To use write, the first argument needs to be an array of type char or a const char pointer. In line 19, I'm using the c_str() function to convert the characters in testString (an STL string object) to a null-terminated array of characters (a C-string). The c_str() function was suggested in another thread as a way to extract the characters in a string object, to put them in a C-string.

The second argument of write is the number of characters (bytes) to write. This can be done in either of two ways:
  1. Use strlen() in the cstring.h header on the C-string. My code includes this header.
  2. Use the length() function on the string object.
In my code I did this both ways, but I have commented out the second way, above.

For the write function, it's tempting to do this:
C++:
outFile.write(Cstr, sizeof(Cstr));
But all this does is to write 4 characters of Cstr to the output stream. I leave it as an exercise for you to figure out why only 4 characters are written.

Other comments:
There was nothing wrong with your choices of outputFile and inputFile. In my version I used slightly shorter names that still convey what they're going to be used for.

The ifstream and ofstream classes inherit from the fstream class, so I have declared both inFile and outFile to be of type fstream , rather than have one stream object be of type fstream and another be of type ifstream. The C++ run time "knows" which type of stream each will be based on the parameters used when you open the streams.

As already mentioned, "emptyFile.txt" is not a good name for a file, since it is not likely to remain empty.
Thanks
Good to know getline() is ONLY for reading. Looks like streaming operator is the ONLY direct way to write std::string to file.

I actually had inFile and outFile, I added that because you said I need to be more descriptive.

I got into habbit to use fstream instead of ofstream and ifstream. I am just reviewing ofstream and ifstream.

Thanks
 
  • #18
yungman said:
Good to know getline() is ONLY for reading.
If you see "get" or "put" in a function name, that's a clue. It's always the same clue. Get gets and put puts. See how that works?
 
  • #19
yungman said:
Looks like streaming operator is the ONLY direct way to write std::string to file.
Yes, but in my code I showed how you can use write to write the contents of a STL string object to a stream. There's one small hoop you need to jump through; namely, extracting the characters from the string object and putting them into a C-string.
yungman said:
I actually had inFile and outFile, I added that because you said I need to be more descriptive.
Those names are just fine. Adding "put" doesn't make them any more descriptive. It was names like nameL, ct2, and similar that I objected to.
yungman said:
I got into habbit to use fstream instead of ofstream and ifstream.
No, in you code you had both fstream and ifstream.
Or maybe what you meant was "I have to get into the habit of using fstream instead of ofstream and ifstream."
 
  • #20
I finally finished revising the notes on read write files. This is the first page, not including binary files and reinterpret_cast<char*>&structure. It is time well spent.
This is the program 12.7 referred to in the notes:
C++:
// 12.7 This program demonstrates how the >> operator work
//with c-string and std::string to and from a file.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    const int SIZE = 81;  // Size of input array
    char input[SIZE];     // To hold file input
    string inputSt, inputSt1, inputSt2;
    fstream nameFile;     // File stream object
//Create murphy.txt
    nameFile.open("murphy.txt", ios::out);
    nameFile << "This is a test\n\n  More test \n\n and test";
    nameFile.close();

// Read into char input[81] from file only once with streaming operator, no loop.
    nameFile.open("murphy.txt", ios::in);
    nameFile >> input;
    count << " Using single nameFile >> c-string: \n   " << input << "\n\n";
    nameFile.close();

// Read into std::string from file only once with streaming operator, no loop.
    nameFile.open("murphy.txt", ios::in);
    nameFile >> inputSt;
    count << " Using single nameFile >> std::string : \n   " << inputSt << "\n\n";
    nameFile.close();

// Read into char input[81] from file using while loop with >> without space.
    nameFile.open("murphy.txt", ios::in);
    count << " while (nameFile >> c-string) count << input \n   ";
    while (nameFile >> input)
    {count << input;}
    count << "\n\n";
    nameFile.close();

// Read into std::string from file using while loop with >> without space.
    nameFile.open("murphy.txt", ios::in);
    count << " while (nameFile >> std::string) count << inputSt \n   ";
    while (nameFile >> inputSt1)
    {
        count << inputSt1;
    }
    count << "\n\n";
    nameFile.close();

//Read into char input[81] with while loop and put space in between
    nameFile.open("murphy.txt", ios::in);
    count << " while (nameFile >> c-string) count << input << " " \n  ";
    while (nameFile >> input)
    { count << input << " ";}
    count << "\n\n";
    nameFile.close();

    //Read into std::string with while loop and put space in between
    nameFile.open("murphy.txt", ios::in);
    count << " while (nameFile >> std::string) count << inputSt2 << " " \n  ";
    while (nameFile >> inputSt2)
    {
        count << inputSt2 << " ";
    }
    count << "\n\n";
    nameFile.close();

//Using cin.getline()
    nameFile.ignore();
    nameFile.open("murphy.txt", ios::in);
    count << " Using nameFile.getline():    ";
    char cAr[31];
    nameFile.getline(cAr, 31);
    count << " Using cin.getline():   " << cAr;//Read until "\n"
    count << "\n\n";
    nameFile.close();
    return 0;
}

Thanks for all the help.
 

Attachments

  • #21
Mark44 said:
For the write function, it's tempting to do this:
C++:
outFile.write(Cstr, sizeof(Cstr));
But all this does is to write 4 characters of Cstr to the output stream. I leave it as an exercise for you to figure out why only 4 characters are written.
Cstr is the ADDRESS, it's 4 bytes!
 
Last edited:
  • #22
yungman said:
Cstr is the ADDRESS, it's 4 bytes!
Bingo! Since Cstr is an address, and it was 32-bit code, sizeof(Cstr) == 4.
 
  • Like
Likes   Reactions: yungman
  • #23
Mark44 said:
Bingo! Since Cstr is an address, and it was 32-bit code, sizeof(Cstr) == 4.
Ha ha, don't say I am not listening and learning! More like leaking out from the old brain! That's why I have to periodically stop and review old stuffs and update my notes. particularly stuffs like files, pointers, and class in the future, I just have a very strong feeling these are very important AND they are the hardest.

Thanks
 
  • #24
yungman said:
particularly stuffs like files, pointers, and class in the future
Files not so much, but definitely pointers and classes. There's still quite a bit more to learn about classes. You've made a dent, you haven't done anything yet with default constructors, copy constructors, overloaded assignment operator, not to mention class inheritance and polymorphism.
 
  • #25
Mark44 said:
Files not so much, but definitely pointers and classes. There's still quite a bit more to learn about classes. You've made a dent, you haven't done anything yet with default constructors, copy constructors, overloaded assignment operator, not to mention class inheritance and polymorphism.
I am surprised files are not as important. One thing, it's not as hard as pointers. I still have not finish chapter 13 on Classes, still have the whole chapter 14 of Classes to go. This is only the first round on Classes, it's my third round in pointers and second round on files! I am sure I will have a lot of upgrades on my notes the second and third go around with Classes. So far, it's not very hard, but like you said, I still have a long way to go.

I tried to play with Constructor, but you guys all said it's bad idea to put file read and write in Constructor and Distructor. I can't find any excuse to use them at this point. Of cause the programs in the book has all the constructor overload and all, but it's very simple and not very educational.

I am looking forward to inheritance and polymorphism (chapter 15) and even chapter 16 on std::string class and templates. I decided to go at least to chapter 16 before I decide what to do next.

thanks
 
  • #26
yungman said:
I am surprised files are not as important.
I'm not saying file I/O isn't important -- just that it's pretty straightforward, and not too much different from file I/O in other high-level languages.
yungman said:
it's bad idea to put file read and write in Constructor and Distructor.
Yeah, it's a bad idea, and BTW, it's Destructor
 
  • #27
yungman said:
I tried to play with Constructor, but you guys all said it's bad idea to put file read and write in Constructor and Distructor. I can't find any excuse to use them at this point. Of cause the programs in the book has all the constructor overload and all, but it's very simple and not very educational.
An example of something you should be doing in the constructor is storing the name of the file you want to work with - at the moment you have this hard coded in 3 different places in your code. Instead I would do something like this:

C:
class Directory {

  private:
    // The name (actually the path) of the file to store the directory.
    std::string _filename = "Directory.dat";

  public:
    // Constructors.
    Directory();
    Directory(std::string &filename);
}
And then your main can do something like this:
C:
int main() {
  // Use the default file.
  Directory directory = Directory();

  // Use a different file for testing.
  // @TODO set this from a command line argument.
  Directory directory = Directory(std::string("test-directory.dat"));

  directory.open();
  directory.add(std::string("John Doe"), std::string("+1-202-555-1234"));
  directory.sort();
  directory.save();
}
 
  • Like
Likes   Reactions: yungman, sysprog and Vanadium 50
  • #28
pbuk said:
An example of something you should be doing in the constructor is storing the name of the file you want to work with - at the moment you have this hard coded in 3 different places in your code

This is good. A few things I would do differently:

(1) Naming the class "Directory". This holds (among other things) a name for a file that sits in a directory that is not the Directory called directory. Confused? That's the point.

(2) Having the class and object named the same (modulo a capital letter). The OP has shown confusion of class vs. object and this may not help. As a general rule, I only do things like this when dealing with singletons: objects where only one instance is possible. You want to avoid "directory", "real_directory", "no_this_is_the_real_directory".

What is very good is that the constructor cannot fail. This is not true if the constructor is opening and reading files. Why does this matter? Because a constructor can't return a status word saying "Hey, there was a problem and I wasn't even created." One needs to throw an exception, and the OP is not got that far. Normally, one would say "do it this way now, and you'll see why this is a good habit to get into after a few chapters", but the OP is tempermentally unsuited to accept this kind of advice - indeed, has rejected it.

Finally, I like the use of STL string objects. I have found that picking one (STL string vs. C string) and using it is better than flipping back and forth, and STL strings have more ways to manipulate them.
 
  • Like
Likes   Reactions: pbuk
  • #29
pbuk said:
C++:
Directory directory = Directory();
This seems redundant to me. Directory directory; invokes the default constructor for class Directory.
 
  • Like
Likes   Reactions: pbuk
  • #30
It is. He calls the same constructor twice.
 
  • Like
Likes   Reactions: pbuk

Similar threads

  • · Replies 75 ·
3
Replies
75
Views
7K
  • · Replies 70 ·
3
Replies
70
Views
5K
Replies
10
Views
2K
  • · Replies 12 ·
Replies
12
Views
2K
Replies
1
Views
6K
  • · Replies 65 ·
3
Replies
65
Views
8K
  • · Replies 32 ·
2
Replies
32
Views
4K
  • · Replies 1 ·
Replies
1
Views
3K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 12 ·
Replies
12
Views
2K