Opening a file in the current directory - c++

I'm trying to load files, and previously I was using hardcoded file locations, (like "c:\location\file.txt") but now that a few friends are also using the file, I'd like to allow them to put the executable wherever they want.
my current code looks like:
ifstream myfile;
myfile.open("c:\\client\\settings.cfg");
I'm trying to change it so that the user puts their executable into whatever folder they want, and then they create a folder and put their settings file into it and the exe will load that with their settings.
ifstream myfile;
myfile.open("\\settings\\settings.cfg");
I have some basic error handling in place, and now the program always errors out saying that it can't find the file.
The file structure looks like this:
[ART]
asset.png
[SETTINGS]
settings.cfg
client.exe
This seems like a really simple thing to do, but I can't find any way to do it. Every example and tutorial about reading and writing to files deals only with files in the executable's directory, or hardcoded into c:\folder...
Could anyone point me to how I do this?

The search path for most systems starts with the current working directory and then to a PATH environment variable. So, all you need to do is specify the file/folder without the absolute path markings and it will use the path relative to the working directory:
ifstream myfile;
myfile.open("settings\\settings.cfg");
// ^^ Note the lack of \\ to start the file path

Paths beginning with \ are always relative to the current drive's root directory. If the current drive is C:, then \settings\settings.cfg means C:\settings\settings.cfg.
Note that you can use / in order to avoid escaping everything. So you can use: settings/settings.cfg. This will be relative to the user's current directory. Note however, that this doesn't necessarily correspond to the directory where the executable resides. If you need the directory of the executable, then you need to use a Windows API function to get it:
#include <Windows.h>
// ...
HMODULE module = GetModuleHandleW(NULL);
WCHAR path[MAX_PATH];
GetModuleFileNameW(module, path, MAX_PATH);
Now if you want to open settings/settings.cfg relative to the directory of the executable, create a path that starts with path and append /settings/settings.cfg to it.

Related

Relative path with fstream c++

I try to load a file with fstream. The code looks like this
file.open("../levels/level0.lvl");
if (file.is_open()) {
while (!file.eof()) {
std::getline(file, Str);
list = ReadLine(Str, list);
}
}
But it loads nothing. Yes only if the path is absolute.
How can I make the path relative?
The folder "levels" is hosted in the debug folder. same folder as the exe.
"The folder "levels" is hosted in the debug folder. same folder as the exe."
It doesn't matter in which position the levels folder is in relation to the executable's path.
The relevant folder to determine the relative path is the working directory where your executable is actually started from.
See here: fstream doesn't resolve path also.
Path handling is OS specific. The correct way to handle this is to add a way of the user specifying the path to your application and then use that path. For example, you could add a command line option --level-file=<path>. Then your program can read the path from that option and pass it to the fstream constructor.
See my answer to this question for more: https://stackoverflow.com/a/40980510/2345997

Qt, read in a local text file

I have tried to use QFile to open a text file:
I tried
QFile file("serial_deviceIP.txt");
but the file.open() returns false.
However, if I switched to a global address like:
QFile file("C:/Users/shupeng/Documents/qgroundcontrol_peidong_mod/serial_deviceIP.txt");
it works. Why? How can I solve this?
In the first instance, the path to the file cannot be found.
QFile file("serial_deviceIP.txt");
This specifies the file with a relative path, and will only work if serial_deviceIP.txt is in the current working directory, which is likely to be the directory that contains the executable of your program.
QFile file("C:/Users/shupeng/Documents/qgroundcontrol_peidong_mod/serial_deviceIP.txt");
This is referencing an absolute file path, so the file will be found
You can also use Qt's Resource System to bundle the files with your application.
Create a .qrc file in your project and add any file you wish to use/load in your application to it.
Then you can load your file as:
QFile file( ":myfiles/serial_deviceIP.txt" );
See QT Resource System for more information.
What happens is that when we are developing our code we usually keep our project source dir on mind as the reference so we don't give an absolute path, but after building the current directory will change and it will be the build directory, so our application won't find the files without a absolute path.
A possible solution is to add a Resources in our project including our project directory. So just add the following line in the project_file.pro:
RESOURCES += ./
and then use the character : before the file's name when you go to read it, like it:
QFile foo(":bar.txt")
That just work for read it but not for write. So to write is necessary specify an absolute path.

How do I use fstream to write to a file above the executable's directory in C++?

I'm trying to write to a file that is not in the directory that the executable is in; I also want it to work no matter where the executable is (I believe that would rule out using ".."). I need this to work on Linux. Thank-you.
This has been asked already, see Get path of executable or Finding current executable's path without /proc/self/exe for a good answer, or search yourself.
Your problem boils down to getting the absolute path to the running executable.
A relative path is usually resolved starting from the running directory, which is not necessarily the executable directory (rather the current directory in the shell from which the executable is launched).
Under linux, you can read the directory of the executable with:
readlink /proc/self/exe
or you could use boost fs::path and fs::system_complete. Then you have to remove from that string the last component, which is the executable name.
Once you have the path of the executable directory, append "/.." to it and you will get the directory above the executable directory.
You can use an absolute path, if you know it ahead of time:
fstream * fs = new fstream("~/config_file");
If the file varies, you can take the path from user input or a configuration file.
Depending on where the file is, whether it moves and where the program is, you may actually be able to use a relative path. From the info you've given, I couldn't tell.
You can do this easily, but you will have to have an absolute path to the file you want to work on, or you will have to create some relative file-structure between your executable and the file you are wanting to access.
Another option is you could, using a forked process or popen(), launch find, and give it the appropriate arguments to locate the document you are wanting to work on, and then use that returned string as the argument to create the fstream object to write to or append to that file.
So for instance, this could look something like:
#include <limits.h>
#include <fstream>
#include <stdio.h>
char buffer[PATH_MAX];
//search the entire file-system starting from the root for "my_specific_file.txt"
FILE* located_file_handle = popen("find / -name my_specific_file.txt -print", "r");
//get the first file returned from the find operation and close the pipe
fgets(buffer, PATH_MAX, located_file_handle);
pclose(located_file_handle);
fstream file(buffer);
If you think there will be more than one file returned from the call to find, then you should cycle though each of them using fgets until you locate the one you want.

Opening a file with a certain program changes that programs working directory?

I have a file saved to my desktop, when I open it with my program the working directory changes to the desktop, this means my program can not load in some files it needs as it searches for these in the working directory. Is there a way I can stop the working directory from changing like this?
There's a flag you can set to avoid the current directory from changing called OFN_NOCHANGEDIR
http://msdn.microsoft.com/en-us/library/ms646839(v=vs.85).aspx
You can just save your working directory at startup and use absolute paths. In fact, it's better to always open files with absolute paths, unless you really want to rely on the current working directory.
You would be better off determining the processes location, then using it as the key for where to find the other files? There are many ways that programs can be launched, which effect the working directory.
See: The answer here for a good description of how to get the processes location and strip out the executable filename (look in the comments)
Essentially, you use:
GetModuleFileName or GetModuleFileNameEx.
and then:
PathRemoveFileSpec to remove the file name
Opening a file doesn't change your current directory. Perhaps you using the common open file dialog? Here is an article that will explain all about how that changes your current directory.
use SetCurrentDirectory to do that.
You can locate the executable by using GetModuleFileName
TCHAR szFileName[MAX_PATH];
GetModuleFileName( NULL, szFileName, MAX_PATH )
... then compute the correct directory
SetCurrentDirectory(path);

Relative path problem for a deployed win32 application

I have written a c++ program and deployed it in say c:\my_app, and my executable's path is c:\my_app\my_app.exe. Say, my_app needs many files such as the_file.txt, which is located in c:\my_app\the_file.txt.
In my executable, I open the txt file as, xx.open("the_file.txt");
Moreover, I have associated my program with let's say .myp extension.
When I'm on Desktop, and want to open a file named example.myp, my program can not see the_file.txt. Because, it (somehow) assumes that it's currently working on Desktop.
Is there any easy way to handle this problem by changing shell command for open in HKEY_CLASSES_ROOT? The naive solution would be to change all file open operations with something like %my_app_location/the_file.txt". I don't want to do that.
Always use a full path name to open a file. In other words, don't open "foo.txt", open "c:\bar\foo.txt". To find the install directory of your EXE use GetModuleFileName(), passing NULL for the module handle.
These days you shouldn't add files to c:\my_app....
Instead use the ProgramData Folder and full paths.
Use SHGetSpecialFolderPathA with CSIDL_COMMON_APPDATA to get the ProgramData folder and the create your program directory and add your files.
You should set current directory for your app's folder with SetCurrentDirectory function. After that you can open file by name without full path