I successfully write to a file in the folder which run example:
// I run "test" executable file in "TestWrite File" folder
const char *path="/home/kingfisher/Desktop/TestWrite File/xml/kingfisher.txt";
std::ofstream file(path); //open in constructor
std::string data("data to write to file");
file << data;
However, If I try to write with dynamic path: *path = "/xml/kingfisher.txt", it goes wrong (in Windows, it will be fine)!! How I can write with dynamic path like above (not a specific path)? Thanks!
If by dynamic you mean relative, you need to get rid of the leading /, since that makes it an absolute path:
path = "xml/kingfisher.txt";
Just be aware that this file is relative to your current working directory so you will probably need to ensure that it is set to /home/kingfisher/Desktop/TestWrite File for this to work.
If, by dynamic, you mean changable, you can change it whenever you want:
const char *path = "/tmp/dummy";
:
path = "/home/.profile"; // Note path, NOT *path
The const simply means you're not permitted to change the data behind the pointer. You're able to change the pointer itself at will.
Not sure what you mean by "dynamic path"; a dynamic path is one that
will be read dynamically (and so will probably be in an std::string).
On the other hand, you seem to be confusing absolute path and relative
path. If the filename begins with a '/' (under Unix), or with a '/'
or a '\\', possibly preceded by "d:" under
Windows, it is absolute; the search for the file will start at the root
of the file system (on the specified drive in the case of Windows). In
all other cases, it is relative; the search for the file will start at
the current working directory. In your example, both
"/home/kingfisher/Desktop/TestWrite File/xml/kingfiger.txt" and
"/xml/kingfisher.txt" are absolute. If the current working directory
is "/home/kingfisher/Desktop/TestWrite File", then
"xml/kingfisher.txt" should find the file specified by the first
absolute pathname.
*path = "/xml/kingfisher.txt"
This is incorrect since it attempts to dereferences your const char* and modify the contents. This is undefined behaviour since the data is const.
Just declare your path to be a std::string to begin with:
std::string path = "/home/kingfisher/Desktop/TestWrite File/xml/kingfisher.txt";
Then later you can assign any other value you like to the std string and it's operator= will dynamically change it's internals for you:
path = "my/new/path";
You can use this with ofstream just as before and if you need to pass it to a function which expects a const char * just pass path.c_str().
Related
I am trying to play a .mod audio file in an executable. I am using the 3rd party BASSMOD .dll. I can get the audio file to play when I provide the full path to the file, but I cannot get it to play when providing a relative path. Here are some snippets.
main.cpp
#include <QCoreApplication>
#include "bassmod.h"
// define file location
const char* file = "C:/Users/Downloads/test4/console/music.mod";
void startMusic() {
BASSMOD_Init(-1, 44100, 0);
BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);
BASSMOD_MusicPlayEx(0,-1,TRUE);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
startMusic();
return a.exec();
}
bassmod.h (relevant snippet)
BOOL BASSDEF(BASSMOD_MusicLoad)(BOOL mem, void* file, DWORD offset, DWORD length, DWORD flags);
The function I'm concerned about is BASSMOD_MusicLoad. As this project stands, the .mod file will play no problem. However, when I try to change the absolute path of the .mod file to a relative path ("music.mod"), the file fails to play. Why is that? I have the .mod file in the same directory as the executable as well as in the directory containing the .pro file -- that didn't seem to be the issue.
Also, maybe I'm missing something related to how files are opened in C++. It looks like the MusicLoad function requires that the second parameter be of type void*. I'm sure there are many different things I could be doing better here. Ideally, I'd like to be able to have file store the relative path to the .mod file and have it play that way so I don't have to hard code an absolute path. In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc, but then I would have to use QFile, I believe, which won't work because I need the type to be void*.
Any help for a beginner would be much appreciated.
EDIT 01: Thank you all for your help! I got it to work (using relative file path, at least). There are two ways to do this. Here's what I did and how I tested it:
The first case makes the assumption that BASSMOD (or whatever external dll you're using) does not handle relative paths.
const char* file = "C:/debug/music.mod"; // same dir as .exe
QFileInfo info("music.mod");
QString path = info.absoluteFilePath();
const string& tmp = path.toStdString();
const char* raw = tmp.data();
Those are the test items I set up. When I run BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);, it works as expected. That's when I hard-code the full absolute path.
When I ran BASSMOD_MusicLoad(FALSE,(void*)raw,0,0,BASS_MUSIC_RAMPS);, it didn't work. So I decided to print out the values for everything to see where it's messing up:
cout << "Qstring path: ";
qDebug() << path;
cout << "string& tmp: ";
cout << tmp << endl;
cout << "raw: ";
cout << raw << endl;
cout << "full char* file: ";
cout << file;
startMusic();
...returns this:
Qstring path:
"C:/myApp/build-Debug/music.mod"
string& tmp:
C:/myApp/build-Debug/music.mod
raw:
C:/myApp/build-Debug/music.mod
full char* file:
C:/myApp/build-Debug/debug/music.mod
Note the difference? When I hard-code the full path to the file, I found that (thanks to #FrankOsterfeld and #JasonC) the current working directory was actually not where the .exe (/debug) or .pro files were located. It was actually in the same directory as the Makefile.
So I just changed it to this: QFileInfo info("./debug/x.m"); and it worked.
Even though the problem wound up being me not knowing where the current working directory was, the solutions by #Radek, #SaZ, and #JasonC helped to find another way to solve this (plus it showed me how to get the working dirs and convert between types). This is a good reference for people who would want to use QFileInfo to determine where you actually are in the filesystem. I would have used this solution if the dll I was using did not handle relative paths well. However...
I wondered if I could apply the same solution to my original code (without using QFileInfo and converting types, etc). I assumed that BASSMOD did not handle relative paths out of the box. I was wrong. I changed the file variable to const char* file = "./debug/x.m"; It worked!
Thanks for the help, everyone!
However, I would still like to get this to work using music.mod from a Qt resources file. Based on the replies, though, it doesn't look like that's possible unless the 3rd party library you're using supports the Qt resource system.
I have the .mod file in the same directory as the executable.
In Qt Creator the default initial working directory is the directory that the .pro file is in, not the directory that the .exe ends up in.
Either put your file in that directory (the one that probably has all the source files and such in it as well, if you used the typical setup), or change the startup directory to the directory the .exe file is in (in the Run Settings area).
Although, based on your new comment below, I guess the problem is deeper than that... I can't really tell you why BASS doesn't like relative filenames but you can convert a relative path to an absolute one before passing it to BASS. There's a lot of ways to do that; using Qt's API you could:
#include <QFileInfo>
...
const char* file = "music.mod"; // Your relative path.
...
BASSMOD_MusicLoad(...,
(void*)QFileInfo(file).absoluteFilePath().toAscii().data(),
...);
In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc
You won't be able to do that because loading resources from .qrc files is a Qt thing and BASS presumably does not use Qt internally (just like e.g. you could not open a resource with fopen), and doesn't understand how to load resources embedded by Qt. I am not familiar with BASS but a cursory glance at this documentation shows that it also has the ability to play data from an in-memory buffer. So one approach would be to use Qt to load the resource into accessible memory and pass that buffer instead.
In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc, but then I would have to use QFile, I believe, which won't work because I need the type to be void*.
Why do you only belive? Read Qt Doc. It will work. Don't use class QFile but QFileInfo.
QFileInfo info(:/resourcePrefix/name);
QString path = info.absoluteFilePath();
void* rawPtr = (void*)path.toStdString().c_str();
I wish my app to write a file in a specified location, and therefore create the appropriate directory if needed.
The create dir operation isn't a problem for me, but I need the dir path.
I could extract if from the file path, but maybe is there a quick/concise/convenient way of doing the full operation?
I repeat, I'm not searching the basic makedir function, but one which would take the filename of a possibly non-existing file, or a simple qt function to extract the dir path string from the file path string, so I dont' have to write a func for such a basic task.
Use the following code:
const QString filePath = "C:/foo/bar/file.ini";
QDir().mkpath(QFileInfo(filePath).absolutePath());
This code will automatically create the path to the specified (nonexistent) file.
QFileInfo::absolutePath() extracts the absolute path to the specified file.
QDir::mkpath() creates the previously extracted path.
If you have a full path to the file and need to extract the folder path, you can do it this way:
QFile file(full_path_to_the_file);
QFileInfo info(file);
QString directoryPath = info.absolutePath();
//now you can check if the dir exists:
if(QDir(directoryPath).exists())
//do stuff
Depending on what exactly you need, you may prefer to use QFileInfo::canonicalPath() instead of absolutePath
Alternatively, you may also use QFileInfo::absoluteDir:
QFile file(full_path_to_the_file);
QFileInfo info(file);
if(info.absoluteDir().exists())
//do stuff
I'm coding with C++ and Qt.
I want to follow the symlink and get the absolute path with QFileInfo.
For example, /usr/local/extra is an symlink for /home/extra.
Then I need to convert /usr/local/extra/my_directory/ to /home/extra/my_directory.
I tried QFileInfo(path).canonicalPath() but it returns the parent directory only.
Use QFileInfo::canonicalFilePath() instead. canonicalPath() always returns the parent directory, while canonicalFilePath() actually includes the file (or directory) itself.
How about QFileInfo::symLinkTarget() ?
QString QFileInfo::symLinkTarget() const Returns the absolute path to
the file or directory a symlink (or shortcut on Windows) points to, or
a an empty string if the object isn't a symbolic link. This name may
not represent an existing file; it is only a string.
QFileInfo::exists() returns true if the symlink points to an existing
file. This function was introduced in Qt 4.2. See also exists(),
isSymLink(), isDir(), and isFile().
After I asked the question, I think I found the solution.
I should use QDir(path).canonicalPath() instead of QFileInfo(path).canonicalPath().
QString QDir::canonicalPath () const Returns the canonical path, i.e.
a path without symbolic links or redundant "." or ".." elements. On
systems that do not have symbolic links this function will always
return the same string that absolutePath() returns. If the canonical
path does not exist (normally due to dangling symbolic links)
canonicalPath() returns an empty string. Example:
// where /local/bin is a symlink to /usr/bin
QString bin = "/local/bin";
QDir binDir(bin);
QString canonicalBin = binDir.canonicalPath();
// canonicalBin now equals "/usr/bin"
QString ls = "/local/bin/ls"; // where ls is the executable "ls"
QDir lsDir(ls);
QString canonicalLs = lsDir.canonicalPath();
// canonicalLS now equals "/usr/bin/ls".
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Creating a directory In C or C++
I want to make a folder that is titled "BobtheBuilder". And then I want to create a text file inside of it. I want to do this without being aware of my path. I don't want to have to type in:
ofstream out("C:/MyComputer/User/Jeff/etc/BobtheBuilder/NewFile.txt");
I want it just to be local to this area where my executable is contained like this:
ofstream out("/BobtheBuilder/NewFile.txt");
is this possible? Do I have to know the whole path name in order to do file management? I feel like this is possible because you can create or open a file that is in the same directory as the program like:
ifstream inf("NewFile.txt");
Or is there a special keyword that fills in the previous path like this:
ifstream inf("FILLIN/BobtheBuilder/NewFile.txt");
Thanks
You can absolutely specify a relative path like "BobtheBuilder/NewFile.txt" without specifying the whole path.
You would however need to create the folder first before the file.
Since creating folders is platform specific and since you're on Windows, you would need to call the CreateDirectory function with "BobtheBuilder" as its parameter.
The folder would then be created in the default working directory of the program which is the same folder where the executable resides.
You can change this working directory using the SetCurrentDirectory function before creating the folder and file.
For creating a directory you can use the C function:
int mkdir(const char *pathname, mode_t mode);
If you can use Boost, then it really becomes easier and more C++ friendly:
bool create_directories(const path& p);
// usage example
boost::filesystem::create_directories("./BobtheBuilder");
As you mention in your question , you can use both absolute and relative paths. It just depends on what is your intention. In your case, you could just do:
boost::filesystem::create_directories("./BobtheBuilder");
ofstream out("./BobtheBuilder/NewFile.txt");
not needing to specify the absolute path at all.
If you often need to manage paths, Boost provides many useful tools for path management. Just as an example, consider the problem you mention in your question: you want to get the full path to the current directory and then append a relative path. You could do this very easily:
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
...
fs::path curr_abs_path = fs::current_path();
fs::path rel_path = "foo/bar";
fs::path combined = (curr_abs_path /= rel_path);
cout << combined << endl;
Assuming the current directory is /tmp/ the previous code snippet would print:
/tmp/foo/bar
operator/= is responsible for appending two paths and returning the combined result.
Do I always have to specify absolute path for objects instantiated from std::fstream class? In other words, is there a way to specify just relative path to them such as project path?
You can use relative paths as well. But they are relative to the environment you call your executable from.
This is OS dependent but all the major systems behave more or less the same AFAIK.
Windows example:
// File structure:
c:\folder\myprogram.exe
c:\myfile.txt
// Calling command from folder
c:\folder > myprogram.exe
In the above example you could access myfile.txt with "c:/myfile.txt" or "../myfile.txt". If myprogram.exe was called from the root c:\ only the absolute path would work, but instead "myfile.txt" would work.
As Rob Kennedy said in the comments there's really nothing special about paths regarding fstream. But here is a code example using a relative path:
#include <fstream>
int main() {
std::ifstream ifs("../myfile.txt");
... // Do something sensible with the file
}
If you have an .exe file running from C:\Users\Me
and you want to write a file to C:\Users\Me\You\text.txt,
then all what you need to do is to add the current path operator ., so:
std::ifstream ifs(".\\you\\myfile.txt");
will work
You can use relative paths. They're treated the same as relative paths for any other file operations, like fopen; there's nothing special about fstream in that regard.
Exactly how they're treated is implementation-defined; they'll usually be interpretted relative to your process's current working directory, which is not necessarily the same as the directory your program's executable file lives in. Some operating systems might also provide a single working directory shared by all threads, so you might get unexpected results if a thread changes the working directory at the same time another thread tries to use a relative path.
Say you have a src folder directly under your project directory and the src folder contains another tmp_folder folder which contains a txt file named readMe.txt. So the txt file can be read in this way
std::ifstream fin("../src/tmp_folder/readMe.txt");
The behaviour is OS specific. Therefore, the best way to handle this IMHO is to make it somebody else's problem. Read the path to the file to open as a string from the user (e.g: command line argument, config file, env variable etc..) then pass that string directly to the constructor of fstream. Document that this is how your program behaves.
I wrote more about path manipulation here: https://stackoverflow.com/a/40980510/2345997
You can specify a path relative to current directory. On Windows you may call GetCurrentDirectory to retrieve current directory or call SetCurrentDirectory to set current directory. There are also some CRT functions available.
On linux also:
// main.cpp
int main() {
ifstream myFile("../Folder/readme.txt");
// ...
}
Assuming the folder structure is something like this:
/usr/Douments/dev/MyProject/main.cpp
/usr/Documents/dev/MyProject/Folder/readme.txt
What I ended up using was a relative path as identified on How to open a file with relative path in C++? which ended up being:
myFile.open("../Release/frequency.dat", ios::in);
*changing myFile to whatever your variable is.