4

I have a Qt program, that has some .txt files inside. In the beginning I just read them from some directory I made, but the time has come, and it become necessary to create a bundle for Mac OSX. I managed to put .txt files inside /Resources in .app directory of bundle with the help of cmake, but I didn't find how to read them from there.

How can I read those files, so I could run that app from everywhere?

fminkin
  • 162
  • 2
  • 10
  • If you want the app to be cross platform, you're better off using [Qt's resource system](http://doc.qt.io/qt-5/resources.html) instead of the Mac-specific app bundle. – MrEricSir Mar 06 '17 at 01:58
  • @MrEricSir I did that, but I can't read from file using ifstreams for some reason. Or Am I doing something wrong? The same approach (through cmake) was successful when it came to .png, but .txt files are not getting read. – fminkin Mar 06 '17 at 02:02
  • C++'s `ifstream` doesn't know how to read from Qt's internal format, but the corresponding Qt file management classes certainly do, such as `QFile`, `QTextStream`, etc. – MrEricSir Mar 06 '17 at 02:14

1 Answers1

6

As @MrEricSir pointed out, it's better to use the Qt resource system along with the native Qt classes for reading files via streams.

However, if you still need to store your data in the separate files, you can simply use the QCoreApplication::applicationDirPath() method which returns the path to the executable and wrap it into your own function in order to respect the application structure on different platforms.

For example:

QString getResourcesPath()
{
#if defined(Q_OS_WIN)
    return QApplication::applicationDirPath() + "/";
#elif defined(Q_OS_OSX)
    return QApplication::applicationDirPath() + "/../Resources/";
#elif defined(Q_OS_LINUX)
    return QApplication::applicationDirPath() + "/../share/yourapplication/";
#else
    return QApplication::applicationDirPath() + "/";
#endif
}

This sample code assumes that:

  • On Windows you are storing resources in the same directory as your executable.
  • On macOS you are storing resources in the Resources directory of your .app bundle. According to the Apple developer docs, executables are stored in the yourapplication.app/Contents/MacOS directory and resource files are usually stored in the yourapplication.app/Contents/Resources. The code simply travels to the Resources directory relatively to your executable.
  • On Linux you are using the standard Linux directory structure utilizing the separate bin and share directories. Of course, you may use the opt directory or don't bundle your application at all – in this case you won't need any conditional inclusions for Linux. For more information read about the Linux Filesystem Hierarchy Standard.
kefir500
  • 4,184
  • 6
  • 42
  • 48
  • That works, thanks. But it seems you can't do it with #elif, it only worked with separate #ifndef for each return, like it stated [here](https://wiki.qt.io/Get_OS_name) – fminkin Mar 06 '17 at 09:05
  • @fminkin Edited the code, thanks for pointing out. The `#elif defined` directive should work. – kefir500 Mar 06 '17 at 09:17
  • Thanks. But how do you include the files in your Qt project and instruct the build system to put them in the appropriate place for each platform to begin with? It's easy to find directories later with QStandardPaths, but how do you get the files deployed into them upon app installation? – Oscar Mar 11 '19 at 21:54
  • 1
    @Oscar You can use [`QMAKE_POST_LINK`](https://stackoverflow.com/a/10058744/2004438), [`QMAKE_EXTRA_TARGETS`](https://stackoverflow.com/a/36438513/2004438) or [`INSTALLS`](https://stackoverflow.com/a/3991210/2004438) for this. – kefir500 Mar 12 '19 at 05:17
  • Thanks for the info. Still seems a bit fussy to determine where files will end up on each platform, but I guess that's unavoidable. – Oscar Mar 12 '19 at 08:25