What would cause ifstream code to fail on OS X? - c++

I have the following code
string fileName = "assets/maps/main.json";
std::ifstream file(fileName);
std::string temp;
if(!file.good())
{
LOG(logERROR) << "Failed to open map file: " << fileName;
//return;
}
LOG(logDEBUG) << "file Char Count: " << file.gcount();
while(std::getline(file, temp))
{
mapString += temp;
}
file.close();
This code works superbly on Windows 8. When I take this program over to OS X, the file fails to open 100% of the time. Or to be more concise, file.good() never returns true. I intentionally commented out the return there to help debugging for later code.
Anyway, this has driven me insane. I cannot figure out why it's failing on OS X. I've tried different directories, re-created the file on OS X to make sure it wasn't an encoding or line-end issue, nothing at all.
What else can I do to debug, or what might I try as an alternative?
I've also checked the file permissions themselves and they are all fine. I have many other types of files in the same directory structure (images, music, fonts) and they all open fine, it's just this JSON file that fails, and any new derivatives of this file also fail.

When you start a program on Linux or MacOSX, the working directory will be wherever the user is. So, if your game needs to find files, you need to make use of the appropriate preference system. Mac has a concept of a 'bundle' that allows a program to come with data files and use find them, you'll have to learn how to make one. You can look inside all the '.app' directories in your /Applications directories for many examples.

Related

How to check if any files are open in a directory?

I am trying to delete all files in a folder, but if a file is left open, it will not delete. I need to check the folder for any open files, write their names to a text document, and then close the open files. As I don't have much experience, I am first trying to check one file in the same folder, then all in the same folder, then all in a different folder. I don't want to be to needy or demanding, so just some help with the first step would be nice.
I don't have a ton of experience coding, but I have tried using fstream and (name.is_open). I may be using them wrong, so I have not yet ruled them out.
// ifstream::is_open
#include <iostream> // std::cout
#include <fstream> // std::ifstream
void checkFiles() {
int done = 0;
while(done != 1){
std::cout << "Enter 0 for continue or 1 for done: ";
std::cin >> done;
std::ifstream ifs ("test.txt");
if (ifs.is_open()) {
// Print that file is open, then close
std::cout << "File is open\n";
std::ifstream.close():
}
else {
std::cout << "File not open\n";
}
}
For this bit of code, if the file is open, it should say "File is open."
If not, it should say "File not open"
Even if I force quit the .txt file, it still says that it is open.
Eventually, I want to have a new file that displays what files were open, as well as closing all the open files.
Standard C++ offers us the filesystem library to handle files and directories (standardized in C++17). However, checking which files are open is not - as far as I can tell - a feature of that library.
The is_open() method for std::fstream's is something completely different than what you're trying to check for: It tells you whether the particular stream object is in an open state (which would mean association with an open file) - and it doesn't use the OS to check which files are open. Typically, it's just a way to check whether you've closed it someplace else in your own program; at most, it might ensure that the OS has not unilaterally closed the OS-side file access handle. So, you won't get anywhere in that direction.
I also believe, though I'm not 100% certain, that Boost doesn't have a library which offers this capability, either. Boost's filesystem library is almost identical to std::filesystem, as the latter was based on it.
So, to the best of my knowledge, you either need to directly use operating-system-specific calls to do this, or look for a library offering this functionality, elsewhere.
If you haven't found anything else, you could track how this is currently done with what's available in userspace. There's a utility called lsof. It's available on some operating systems based on Linux, Darwin, FreeBSD and Solaris (e.g. available on MacOS). It's maintained here. The source code seems to be rather atrocious C. An intrepid developer could parse that mess, figure out what it does, extract the parts relevant for your specific use case, and refactor it into a reasonable, readable and short(ish) C++ function. I realize you (OP) might not be up for it at this point, but - maybe someone else reading this answer will get inspired to do it.
The pfiles command shows the open files for a process. You can run it for all or some processes.
However, Solaris (and UNIX) in general allows you to delete open files. The file can still be read and written while it is open (but deleted), but nobody else can open the same file and the file will be deleted when all processes have the file closed.

C++ directory search

So I'm trying to write a little C++ program to check whether or not a directory exists on a Windows platform (I am aware that other languages are more suited for this type of use, but I want to do it in c++).
This is what I have so far (it compiles):
std::string DirectorySelector::SpecifyDirectory(void)
{
std::cout << "Enter directory for file renaming: ";
std::cin >> directory;
if (ValidateDirectory(directory) == 1) { SpecifyDirectory(); }
else { return directory; }
}
int DirectorySelector::ValidateDirectory(std::string directory)
{
error = "Error 01: Directory not found.";
std::ifstream fin (directory);
if (!fin)
{
std::cerr << error << "\n\n";
fin.close();
return 1;
}
else
{
fin.close();
return 2;
}
}
So obviously I'm currently asking for the user to input their desired directory as a string, not sure if this is a wise choice?
I have done a little research into whether Windows folders (directories) have an extension, but it appears not.
I assume I am missing something obvious, such as a predefined C++ keyword to use somewhere?
If any answers could be fully explained as to what is going on that would be fantastic, as I don't like to use stuff which I don't understand.
Plus any tips to do with coding standards that I may not be adhering to would obviously be greatly appreciated.
Thanks in advance.
If you want to use DIRENT (unix method) in windows then see here, advantage is cross platform (dirent is pretty much everywhere except windows):
http://www.softagalleria.net/dirent.php
If you want to use the Windows API for this:
How to check if directory exist using C++ and winAPI
For a portable (across many platforms) file-management system you could use boost::filesystem
The documentation may look a bit complex for a relative beginner but they probably give you examples that will enable you to get going on what you want, and if you get stuck you can always come back here and ask specifics.
Your existing code is incorrect in its use of ifstream which is used to open a file for read-only. You cannot use this to open a directory (to list its contents or see if it exists).

Having trouble with fstream in Xcode

I'm having trouble validating the existence of REGISTER.txt for input purposes in a function (see below). My understanding is that if the file doesn't exist, then the file won't be opened and the file stream variable (inData) will be false. Thus, I can use that variable in an if/else statement to verify whether or not it opened. But even though REGISTER.txt is in the same directory as my .cpp file, my code still says that it wasn't opened.
Here's the thing though. When I run the same exact code in Dev-C++ compiler, it works fine and the file is found. Now, I understand compilers are different, but I don't understand what is causing the discrepancy here. My preferred IDE is Xcode, so I'd like to learn how to do I/O with files in Xcode.
Thanks in advance for the help.
P.S. My Xcode project references the file, so it's not like the project isn't connected with the file.
void ReadVehicleRegInfo(char& vehicleType, string& licensePlate,
int& modelYear, float& origTaxValue, bool& error)
{
ifstream inData;
string inputFile = "REGISTER.txt";
inData.open(inputFile.c_str()); //File contains registration info
if (!inData) {
//File does not exist. Exit function
cout << inputFile << " does not exist. Program will now terminate"
<< endl << endl;
error = true;
return;
} else {
//File exists - continue with program
cout << inputFile << " found";
}
inData.close();
}
In my main() function, I have the following code to signal to the user that an error has occurred:
if (error) {
//Function encountered error. Exits program
system("PAUSE");
return 99;
}
EDIT
I spent 40 minutes trying to figure this out, 15 writing the question, and 5 minutes after I post it I make huge progress. Don't you love that?
I put in the full directory to the file and that did the trick.
However, this is not ideal. The next question is how do I avoid having to do that? What is the default directory for Xcode?
Normally it would be the directory where your program lives. If you want to make sure, use _getcwd to get the current directory or just include the parent directory.
char *_getcwd(
char *buffer,
int maxlen
);
However, you should try not to use the full path for the reason it might not be the same when you run your program on another computer.
REGISTER.txt is in the same directory as my .cpp file
REGISTER.txt needs to be in the same directory as the binary (build/Release or elsewhere depending on your build settings)

Xcode c++ cant access file through code

I have added an image "padimage.png" to my resources folder and set add to target and make copy if needed checked. Then in my c++ code I have the following code to check if it can reach the file
std::ifstream my_file("padimage.png");
if (my_file.good())
{
std::cout << "could read file \n";
} else {
std::cout << "could not read file \n";
}
This fails meaning I can't reach the file. I have checked in the debug build folder and the image is there under the resources folder, I have also tried alternative paths to the file like "resources/padimage.png" || Resources/padimage.png || ../Resources/padimage.png etc. etc.
I am fairly new to c++ still so I don't quite understand how it is suppose to find files or what path it searches relative to. Also I am sure this is quite an easy problem but I somehow can't solve it.
All help is much appreciated.
Just for your own sanity, do the following before anything else.
char wd[1024];
std::cout << getcwd(wd, sizeof(wd)) << std::endl;
You may be surprised at where you are, and thus why you can't open your file. When running from the IDE you can specify the location of your working directory under the Product/Edit Schemes... area of Xcode (among other places).
Thanks to a suggestion from WhozCraig I have managed to get it working by using the root of the project and then creating a standalone file next to the application like so:
./padimage.png
however this is not ideal. This means I would have resources outside of the project.
But after some trial and error I managed to navigate into the programs package contents by using .app to the package name;
./ProjectName.app/Contents/Resources/padimage.png

Ifstream open() doesn't set error bits when argument is a directory

In a C++ program, using std::ifstream, I'm attempting to open a user-specified file -- so far so good. However, I accidentally entered a filename that's actually a directory, and I was quite surprised to see that attempting to open() that directory didn't generate any errors.
Here's a minimal example:
std::ifstream f;
f.open("..");
if(!f.is_open() || !f.good() || f.bad() || f.fail()) {
std::cout << "error bit set on open" << std::endl;
return 1;
}
No sign of error here. If I go on and attempt to getline(), getline() sets an error bit all right.
std::string str;
getline(f, str);
if(f.eof()) std::cout << "getline set eofbit" << std::endl;
else if(f.bad()) std::cout << "getline set badbit" << std::endl;
else if(f.fail()) std::cout << "getline set failbit" << std::endl;
This outputs "getline set badbit", which is reasonable. Using the >> operator throws an underflow exception, which is also okay.
Now, my question is, how could I detect that the user entered a directory name instead of a proper filename? Is there any way to do that? Getting and ungetting bytes from the stream seem tedious and error-prone.
Also, why is this so? I realize that it's all just the same data from the point of view of the program, but I'd assume the OS would also send some "hey, this is a directory" kind of message.
You don't say what your system is, so it's hard to say, but generally,
filebuf::open will only return an error if your system level open
fails. And I've worked on Unix systems where you could open() a
directory; I've even worked on some where you could read it after the
open (at least if it was a locally mounted filesystem).
As to what to do about it: about all I can think of is to try to get
the first character, then put it back. But this fails if the file is
empty, so it's not really a solution either. At the system level (and
from a QoI point of view, I'd expect filebuf::open to do this if the
system did allow opening a directory), you can use a system level call
(stat in Unix) to determine whether the file is a directory or not.
(There's a race condition, of course: between the moment you detect that
it's a normal file, and the moment you do the open, another process
could delete the file and create a directory. It's probably not a
frequent occurance, however.)