Checking existence of a txt file with C++ code - c++

First of all, i'd to establish that i do have the text file in my Folders directory. Im using visual studio and it is where my source code is compiling.
The code below should demonstate why its not working. In visual studio.
int main( const int argc, const char **argv )
{
char usrMenuOption;
const char *cFileName = argv[ 1 ];
checkName( cFileName ); // supplying the checkName function with contents of argv[1]
usrMenuOption = getUsrOption(); // calling another function
fgetc(stdin);
return 0;
}
ifstream *openInputFile( const char *cFileName )
{
// this function might be the pronblem.
ifstream *inFile;
inFile = new ifstream;
inFile->open( cFileName, ios::in );
return inFile;
}
bool checkName( const char *cFileName )
{
// it works fine if i use a regular ifstream obj and not the one from the function
ifstream *inFile;
inFile = openInputFile( cFileName );
inFile->open( cFileName, ios::in );
if ( inFile->good() )
{
return true;
}
else
{
cout << '"' << cFileName << '"' << ": File does not exist! " << endl;
return false;
}
}
It does work if i use a non-pointer object for the ifstream.
however i need to open all of my input files this way, using the function i made.
I'm a little confused because i did not have this issue compiling in dev-cpp

You have a few options:
The one you've tried - opening the file.
Using stat.
Using GetFileAttributes.
Using FindFirstFile.
The only way to guarantee that it exists and that you can use it is to open it. If you use other methods you end up with a race condition (because the file could be deleted or locked after you check to see if it exists.
EDIT: You have a couple of other issues in your code. Firstly, you allocate a infile via new, but you never delete it. Secondly, you call open twice.

That's a poor way to test for existence: because if the file is open by another process, then the file exists but you can't open it.
A better way to test might be to use the GetFileAttributes Function: if it doesn't return INVALID_FILE_ATTRIBUTES then the file exists.

If you don't mind using Boost, there is a simple function boost::filesystem::exists( path ) that would be useful to you I guess !

I always check ifs.is_open() where ifs is a ifstream.

To check for the existence of a file (POSIX.1 compliant):
#include <unistd.h>
if (! access (file_name, F_OK))
{
// File exists.
}

How do i check if a file exists using ANSI C++?
#include <fstream>
inline bool FileExists(const char * filename)
{
return std::ifstream(filename);
}

You're trying to open the file twice inside checkName(): the first time in the constructor call inside the call to openInputFile(), the second time inside checkName() itself. Why the second call to open()?
I don't know what happens when an ifstream with an already-open file attempts to open() another file, but it won't be good, and it may well depend on the exact library implementation (hence the different behaviour between Dev-C++ and MSVC++). In short, don't do it.
There is at least one other bug: You aren't closing inFile anywhere inside checkName().
But Anyway, Do This Instead
Really, it's better not to have a separate checkName() function -- just have openInputFile() attempt to open the file, and if it fails, report the error right there and/or return a NULL pointer (or even throw an exception). That way, the operation is "atomic" -- as things stand, if the file exists at the time checkName() is called but is deleted before a subsequent call to openInputFile(), your code will get very confused.

Related

How to make code detect if a file exists or not in C++ 17?

I am new to C++ and I want to make my first game. I want to make a simple savegame system for it but I am struggling to make it see if a savegame already exists or not.
What I have for now
#include <iostream>
#include <time.h>
#include <windows.h>
#include <fstream>
using namespace std;
int main()
{
/*command goes here*/ {
cout<<"<System>: Welcome! Please register."<<endl;
cout<<"(TIP: Username and password can be anything. Both will be saved in your savegame [Savegame.txt] and you will be automatically logged in.)"<<endl;
Sleep(2000);
ofstream ("Savegame.txt");
ofstream fout;
fout<<"Username: ";
cin>>name;
cout<<name<<endl;
cout<<endl;
cout<<"Password: ";
cin>>password;
fout<<password<<endl;
}
else
{
cout<<"<System>: Welcome back!"<<endl;
ifstream fin;
fin>>name;
fin>>password;
}
return 0;
}
Please help I am trying to do this for a week :(
You need to #include <filesystem> and then use the appropriate function, e.g.
const bool exists = std::filesystem::exists("myfile.txt");
It might also make sense to narrow the query a bit, as in
const bool exists = std::filesystem::is_regular_file("myfile.txt");
The latter subsumes the existance of the file.
use the exists method:
std::filesystem::exists
example:
const bool exists = std::filesystem::is_regular_file("myfile.txt");
Eventually, if you want to target older versions of C++, you can open the file in read mode, then check if it's open or not.
If it's open, it exists and you have your answer, otherwise it may be non-existent or have some kind of error during opening.
If so, you can try to open it in another mode and verify if it fails again or not, to rule out or verify your guess.
At least, that's what i did before standard version 17 (from C++11 in this example constrained by raw string in path which can be removed simply escaping the path).
e.g.
string path = R"(...<my path>...)";
std::fstream fp;
fp.open(path, std::fstream::in);
if (fp.is_open()) {
// file exists
fp.close();
}
else {
fp.open(path, std::fstream::out);
if (fp.is_open()) {
// file has been created
fp.close();
}
else {
// other error occurred
}
}
As already pointed out, Filesystem Cpp official reference allows you to have the full range of operations available, for this particular instance:
bool exists( const std::filesystem::path& p );
bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept;
If you use std::filesystem::exists without error code, be careful to catch and eventual std::filesystem::filesystem_error (could happen trying to inspect files in removable devices or if special conditions applies).
bool existing_save = std::filesystem::exists("Savegame.txt");
What i think you may missing is to correctly configure Visual Studio to use the right C++ set, which can be done by clicking menu Project -> "your project name" Properties that will open a window in which you can edit General properties -> C++ Language Standard and set C++17 instead of the default C++14.
You can see what to do in the image below, hoping this could help you:

c++: ifstream delete contents of a file? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am using following function:
int getline_count()
{
boost::smatch resultc;
string sLine;
int line_add_tmp;
ifstream infile;
infile.open("scripts.txt", ios_base::in);
if (!infile){
cerr << "scripts.txt could not be opened!" << endl;
}
else {
getline(infile, sLine);
if (boost::regex_match(sLine, c)) {
line_add = 2;
}
else {
line_add = 1;
}
return line_add;
infile.close();
}
}
Intension for the above function is to test if the first line in the file contains '// new' If true, 2 is returned. If false, 1 is returned. This works fine so far.
What I am confused about is that after the run the file scripts.txt is empty. How can that be since
1.) The '// new' line was correctly identified as I am getting '2' returned (running on an empty file returns 1 as expected). So it can't be that during opening the file scripts.txt it was overwritten with an empty file
2.) ifstream was designed to read only
What is it what I am missing?
Edit:
Definition for c is
static const boost::regex
c("^(\\/)(\\/)(new|New| new| New)"); // Regexp for line count
An ifstream should never manipulate your file. You will need to look elsewhere for your problem, it's not inside this code. Your best bet is to provide a Minimal, Complete, and Verifiable example that demonstrates your problem.
However, you should check your coding, you are missing essentials like error handling and treating compiler warnings. Most likely, if your other code looks the same, that's the source of your problem.
Personally, I'd write your function like this:
bool first_line_in_file_matches(const std::string& filename, const boost::regex& c)
{
std::string line;
std::ifstream infile(filename.c_str());
if (!infile)
{
cerr << filename << " could not be opened!" << endl;
// TODO: THROW AN EXCEPTION MAYBE? OR RETURN FALSE? EXIT HERE
}
return getline(infile, line) && boost::regex_match(line, c);
}
This function will not clear the contents of the file. So if in fact the file is cleared it is cleared externally to getline_count.
To prove this lets inspect the functionality of each call on ifstream relative to the file:
ifstream::open This will only clear the file if the mode is set to ios_base::trunk
ifstream::operator bool This is a const method so the ifstream cannot be modified
ifstream::getline TLDR: This can only extract, not write to a file:
Internally, the function accesses the input sequence by first constructing a sentry object (with noskipws set to true). Then (if good), it extracts characters from its associated stream buffer object as if calling its member functions sbumpc or sgetc, and finally destroys the sentry object before returning.
ifstream::~ifstream This is implicitly declared, so it simply destroys the object, closing the file; if this deleted file contents no one would ever have been able to use an ifstream
The recommended steps to finding the culprit of the file clearing are:
Ensure that you are looking at the correct file and don't have some process external to your code which is clearing the file
Search your code for "scripts.txt" something else has to access the file by name and debug it
Disable writing to "scripts.txt" and see if you can locate the code that fails to write to the file

How can I switch between fstream files without closing them (Simultaneous output files) - C++

I have a little C++ issue that I couldn't solve by browsing online. Here is my code (extracted):
if(File.is_open()) {
while(!File.eof()) {
i++;
getline(File,Line);
if(i>=2) { //Skip Headers
int CharCount=0;
for(int CharPosition=0; CharPosition<Line.size(); CharPosition++) {
if(Line[CharPosition]==',') {
Length=CharPosition;
break;
}
}
NameText=Line.substr(0,Length);
Path= Path_Folder + "\\" + NameText + ".csv";
if(!CheckExistance(Path.c_str())) {
fstream Text_File;
}
Text_File.open(Path, fstream::in | fstream::out | fstream::app);
Text_File<<Line<<"\n";
Text_File.close();
}
}
}
This code is working fine, but I would like to change the fact that it closes the Text_File every time it goes in the while loop.
Basically, this program split a big input file in a lot of smaller files. As my
smaller files get bigger and bigger, the execution gets slower and slower
(normal). My goal is then to let all the smaller files (Text_File) opened in
this while loop and just switch the fstream pointer (pointer?) from one to
another.
I tried to change as:
...
NameText=Line.substr(0,Length);
Path= Path_Folder + "\\" + NameText + ".csv";
if(!CheckExistance(Path.c_str())) {
fstream Text_File;
}
if(!Text_File.open()) {
Text_File.open(Path, fstream::in |fstream::out | fstream::app);
}
Text_File<<Line<<"\n";
\\Text_File.close();
...
But it is working on the same Text_File no matter what NameText is. So I am guessing that the pointer of the fstream Text_File doesn't change. What do I need to be then? Rest the pointer? How?
Thank you, all!
Not sure it is relevant but I am working with Microsoft Visual C++ 2010 Express.
In addition, I am not a programmer neither by education nor by living, so if you can explain it without too advanced words, I'll appreciate.
It looks like you would like to juggle the filebufs on an ostream object.
Now, the only obstacle is that ostream or basic_filebuf<char> aren't copyable types, so you can't put them into a map (by filename) directly. This is easily worked around by creating a little Holder type:
struct Holder {
Holder(std::string const& path)
: buf(std::make_shared<std::filebuf>())
{
buf->open(path.c_str(), std::ios::out | std::ios::app);
}
std::shared_ptr<std::filebuf> buf;
};
std::map<std::string, Holder> buffers;
Now the complete program (tested) would look like this:
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <memory>
const std::string Path_Folder = ".";
int main()
{
std::istream& File = std::cin; // just for example
std::filebuf dummy;
std::ostream TextFile(&dummy);
struct Holder {
Holder(std::string const& path)
: buf(std::make_shared<std::filebuf>())
{
buf->open(path.c_str(), std::ios::out | std::ios::app);
}
std::shared_ptr<std::filebuf> buf;
};
std::map<std::string, Holder> buffers;
int i = 0;
std::string Line;
while(getline(File, Line))
{
if (i++<2)
continue; //Skip Headers
auto NameText = Line.substr(0, Line.find(','));
auto Path = Path_Folder + '/' + NameText + ".csv";
// open, only if not allready opened
auto found = buffers.find(NameText);
if (end(buffers) == found)
found = buffers.insert({ NameText, Path }).first;
TextFile.rdbuf(found->second.buf.get());
TextFile << Line << std::endl; // notice implicit std::flush in std::endl
}
// all files are automatically closed here
}
Three more notes:
files get automatically closed when the buffers map goes out of scope.
you might need to add explicit flushes when switching rdbuf() like this, if you don't end your lines with an implicit std::flush (like with std::endl).
dummy only exists to have an ostream object that we can switch the buffer of
I tested this with the following input:
Header Row #1
Header Row #2
Jack,1,some data
Jill,2,some more data
Jack,3,not reopening :)
Jill,4,jill still receiving output
Romeo,5,someone else reporting
Now, I got the following output: see it live at Coliru
/tmp$ rm *.csv
/tmp$ make && ./test < input.txt && tail *.csv
g++ -std=c++11 -Wall -g test.cpp -o test
==> Jack.csv <==
Jack,1,some data
Jack,3,not reopening :)
==> Jill.csv <==
Jill,2,some more data
Jill,4,jill still receiving output
==> Romeo.csv <==
Romeo,5,someone else reporting
Note: it looks like your Text_File is out of scope. I guess you declared it somwhere else in the code. So, this line is useless:
if(!CheckExistance(Path.c_str())){fstream Text_File;}
To access multiple file streams you can use this simple class which utilizes the std::map data structure:
#include <iostream>
#include <map>
#include <string>
#include <fstream>
class StreamWriter
{
typedef std::map<std::string, std::fstream> StreamMap;
static StreamMap Files;
public:
static std::fstream& GetFile(const std::string& filename)
{
std::fstream& stream = Files[filename];
if (!stream.is_open())
{
stream.open(filename, std::fstream::in
| std::fstream::out | std::fstream::app);
}
return stream;
}
};
StreamWriter::StreamMap StreamWriter::Files = StreamWriter::StreamMap();
Then, access to files is as simple as:
StreamWriter::GetFile("C:/sample1.txt") << "test";
That's it.
What I would do is use std::map or std::unordered_map to map names to fstream objects.
map<string, fstream> files;
...
while(getline(File,Line)) // don't use while(File.eof())
{
...
if( files.count(NameText) == 0 ) // checks for the existence of the fstream object
{
files[NameText].open(Path, fstream::in | fstream::out);
}
files[NameText] << Line << "\n";
}
See here for why I changed the condition for the while loop.
Your OS may have trouble having that many open files at once. Perhaps you could try something like this.
Alongside your map, keep a list of the names of the files that are open. Each time you need to write to a file, first search for it in your list, remove it and add it to the front of the list. If it's not there, just add it to the front of the list. Check to make sure the file is open. If it's not, then try to open it. If opening it fails, then one by one, remove items from the back of the list, close the corresponding file to that item, and try to open the current file again. Repeat until opening the file succeeds.
Doing this will ensure that the most frequently written to files stay at the front of the list and remain open. The less frequently written files will move to the back, and eventually be closed. The search for the file in the list is not optimal (O(n)), but since we're dealing with writing to files here, which is a much more expensive operation, you shouldn't notice any kind of perf hit.
You are trying to reuse the Text_File fstream. To do this, you have to do a close() to flush the stream, after you are done writing to a csv file. Please see this question: C++ can I reuse fstream to open and write multiple files?
Also: Here's my Google search for this question: http://goo.gl/Oy5KKM
Note that Text_File is a variable and like all variables you can have more than one with the same type. If you need to manage several different files, you can even use std::fstream in any of the standard containers such as std::vector or std::map. Also, you should consider breaking your code down into smaller more manageable parts. For example, you can create a function which takes an std::fstream& as a parameter. This allows the rest of the program to control which std::fstream& is used at any given time. I strongly suggest that you look at different design options to help organize your code.
The existence check statement has no effect - as mentioned already. Perhaps your intention was to do something like this:
if(!CheckExistance(Path.c_str())) {
fstream Text_File;
Text_File.open(Path, fstream::in | fstream::out | fstream::app);
Text_File<<Line<<"\n";
Text_File.close();
}
The fstream within the scope of if statement will hide the one you must have in the outer scope. Also, close is optional - stream will be closed when it goes out of scope.

Fstream Initialization in a Class - Checking if File Opened

Example:
//Header File
class Example
{
private:
fstream InputObject;
public:
Example();
}
//Implementation File
Example::Example():InputObject("file_name.txt", ios::in) {}
From what I've read so far from similar questions, the only way, in the "older" version of C++, for initializing an fstream object in a class is to do so via member list initialization shown above.
Question:
If that really is the "only" way of initializing an fstream object in a class, what do we do if the file should fail to open?
Normally I'd run the fstream object through a check to make sure it opened properly, but this doesn't seem possible in this case. Also, even if I could, how could I reinitialize the object if it failed to do so the first time through?
#define WIN32_LEAN_AND_MEAN // This makes it so it doesn't look through libs that are not included when running
#include <fstream> //To Read write to files, to be able to
#include <iostream> // The basic stuff, cout, cin, etc.
using namespace std; // the capability of typing cout instead of std::cout
int main() // our main loop
{
fstream InputObject; // declaring InputObject as something that can write to a file
if(!Inputobject.open("File Name Here") // if it cant open the file
{
cout << "File not Open" << endl; // then write to console, " File not Open"
}
return 0;
system("pause");
}
You want to find out if the file is open, so using ! before the functio for opening file means , not open, so an if statement with !InputObject.open, will check if it is not open, if that is true, do something, so cout << "File is not open" will tell u if it is open or not.
From what I've read so far from similar questions, the only way, in the "older" version of C++, for initializing an fstream object in a class is to do so via member list initialization shown above.
That's not strictly true.
It is probably the preferred way of doing it. But you don't need to do it that way. And a failure simply sets the state to failed that can then be tested in the body of the constructor.
If that really is the "only" way of initializing an fstream object in a class
No.
what do we do if the file should fail to open?
Test and re-try in the body of the constructor.
Normally I'd run the fstream object through a check to make sure it opened properly, but this doesn't seem possible in this case. Also, even if I could, how could I reinitialize the object if it failed to do so the first time through?
There are standard API to reset the state of a stream after a failure.
Example::Example()
:InputObject("file_name.txt", std::ios::in)
{
if (!InputObject) {
InputObject.clear();
InputObject.open("AlternativeFile", std::ios::in)
}
}

fstream won't print to file

The following code will print something to a file
std::fstream fout ("D_addr.txt", std::fstream::app);
fout << pkt->Addr() << std::endl;
flush(fout);
fout.close();
While debugging, I watched pkt->Addr() and it has some values. The fout line is passed without problem. Also the file D_addr.txt is created. However after closing the file, the file size is zero! nothing has been written to it.
Where is the problem?
This is not your actual code I guess and if it is I would start with that Addr() function of yours.
Note that fstream::close "closes the file currently associated with the object, disassociating it from the stream. Any pending output sequence is written to the physical file." flush(fout); can be omitted.
You should also specify std::fstream::out flag. "If the function is called with any value in that parameter the default mode is overridden, not combined." So instead of std::fstream::app you should pass std::fstream::app | std::fstream::out.
I'm wondering if you're not using the wrong class. If you want to write to a file, use std::ofstream, and not std::fstream. In particular, the constructor of std::ofstream forces the ios_base::out bit when calling rdbuf()->open; the constructor of std::fstream doesn't (so you're opening the file with neither read nor write access).
And you probably want to check the error status: did the open succeed, and after the close (or the flush), did all of the writes succeed. The usual way of doing this is just:
if ( fout ) {
// All OK...
}
if ( !fout ) {
// Something went wrong.
}
After the open (the constructor), you can use fout.is_open(), which has the advantage of being a little bit more explicit with regards to what you are checking for.
First of all, flush() and fout.close() do not make any harm, but are not needed here, because when fout gets destroyed the file will be closed (and flushed) as part of fstream destructor.
Second, you should use an ofstream or alternatively add the flag std::ios::out to the openmode parameter.
Try something along the lines of:
{
uint64_t x = 42;
std::fstream of("test.txt", std::ios::app);
of << x << std::endl;
}