How to copy qrc resource file into filesystem? - c++

I wonder how to copy file that is embeded into app qrc into fs? Stuff like
QFile::copy("qrc:/assets/files/my.file" , "C:/my.file");
seems not to work. Why and how to make it to?

You don't need the qrc, resources start with a :
eg QFile myFile(":/data/data.xml");
PS: I'm not sure how QFile treats case sensitiveness on resource filenames. For best portability you might want to make sure the case matches whatever is in your qrc file.

Related

How to access Qt resource data from non-Qt functions

As I understand it, the way to packages non-code resources such as data files in a Qt app is using the resource system. However, what if I want to access a resource using a non-Qt function. For example, I may have a .txt or .csv file with some application data that I want to accessing using ifstream. It doesn't seem to work to use the ": ..." syntax in place of a filename for non-Qt functions and classes. Is there a separate workflow for packaging data used by non-Qt functions in an app?
I'm using OSX, but I would assume these issues are platform independent.
The sole purpose of the Qt resource system is to bundle data within the executable itself. If you wish not to integrate the data in the executable, then you simply must not use the resource system.
On mac, if you wish to add "data.txt" from project source to your application bundle, but not to the executable itself, add the following to your .pro file:
mac {
BUNDLE = $$OUT_PWD/$$TARGET$$quote(.app)/Contents
QMAKE_POST_LINK += ditto \"$$PWD/data.txt\" \"$$BUNDLE/Resources/\";
}
Given the above project file, use the QCoreApplication::applicationDirPath() for a path useful in getting to the file:
#include <QCoreApplication>
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << QCoreApplication::applicationDirPath();
QFile data(QCoreApplication::applicationDirPath() + "/../Resources/data.txt");
if (data.open(QIODevice::ReadOnly | QIODevice::Text))
qDebug() << data.readAll();
return 0;
}
In the above example, the Resources folder has nothing to do with the Qt resource system. It's simply a naming convention in OS X application bundles. We're not using the Qt resource system here.
If you wish to use the Qt resource system and access the resource data directly and not through a QFile, the QResource class provides access to resources that are bundled in the executable.
If the code under your control insists on using ifstream for data input, then it's artificially limited and should be fixed. It should use istream instead, as that class can be backed by anything, not necessarily a file. If it's code that you don't control, you could set up the ifstream on a QLocalSocket.
You can map the constant QResource::data() to an input stream via a stream buffer.
If the resource isCompressed(), then you need to first decompress it to a temporary area. You can also disable resource compression to avoid the decompression step. You can use a whole-executable compressor like upx instead - by the time your code runs, everything will be already decompressed and ready to use.
You can copy the resource file into a temporary folder. To do this, use a QTemporaryDir which creates a temporary folder and deletes it automatically when the program is finished. To access the path of that folder, use the QTemporaryDir::path() method. Here is an example of how you can use it:
#include <QTemporaryDir> //You need to include this header
QTemporaryDir temporaryDir;
//Copy the resource file into the temporary folder
QFile::copy(":/exampleprefix/examplefile.txt", temporaryDir.path() + "/examplefile.txt");
//Read the file
std::ifstream fileStream(QString(temporaryDir.path() + "/examplefile.txt").toLatin1().data());
//etc
What about opening the resource file with a QFile object, wrapping this with a QDataStream object, and wrapping this with a boost::iostreams::stream object, which derives from a specialization of std::basic_istream? Sounds complicated, but does not need too many lines of code, see this answer.

Exporting SVG into the local Resource directory

I am trying to reach the qt resource folder without success. It works if I export into an other folder like C:\\Temp\\18_25_21_18_09_2014.svg, but it doesn't work if I use an URL like :/Temp/18_25_21_18_09_2014.svg.
Here is the code:
QString fileName(":/Temp/Temp" + QDateTime(QDateTime::currentDateTime()).toString("hh_mm_ss_dd_MM_yyyy") + ".svg");
QSvgGenerator generator;
generator.setFileName(fileName);
generator.setSize(this->size());
generator.setViewBox(QRect(QPoint(0,0), this->size()));
generator.setTitle(tr("bubble_svg"));
generator.setDescription(tr("bubble_svg"));
_painter.begin(&generator);
_painter.setRenderHint(QPainter::Antialiasing);
_painter.setRenderHint(QPainter::HighQualityAntialiasing);
this->render(&_painter);
_painter.end();
Also I created a prefix called Temp and a folder called Temp.
It looks like that also QDirIterator can reach the folder, only the QSvgGenerator couldn't.
QDirIterator it(":/Temp/Temp", QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
qDebug() << "FILE FOUND " << it.next();
}
The result of this part of code:
FILE FOUND ":/Temp/Temp/18_35_19_18_09_2014.svg"
I appreciate every idea. Thanks for dropping by and taking time with the questions!
Ok, I understood and post it as answer.
Unfortunately it is impossible. Qt Resource System forbid this. As documentation said:
The Qt resource system is a platform-independent mechanism for storing binary files in the application's executable. It means that resources are read only, thuis files compiled into the executable, you can't write it because this files storing in your exe file. Especially an executable can’t modify itself while it is running. You’ll have to re-compile the QRC file (using RCC) and then re-build the EXE file, if one of the resources has changed.
As you can see, you should provide another way to storing and using your files.
I hope it was useful for you.

How to use Qt/C++ to create/read/write files and store settings local with the program

I'm an unfortunate beginner at C++ and using the Qt GUI designer program seemed perfect for my needs, except I'm having problems trying to write out the code necessary for this. I could use the QSettings string to store local settings on the hard drive, but I personally hate it when programs do the %HOME_LOCAL%\APPS_SETTINGS bull that some do. I need to save a text file for both settings and a local\host database, within the program directory, to remember strings to read from later.
What is the line of code I need to make use of a local host text database or is there a better option? And how can I store that with the local program inside its directory?
You can use QSettings with any file, with constructor QSettings::QSettings ( const QString & fileName, Format format, QObject * parent = 0 ).
To get the program directory, you can use QCoreApplication::applicationDirPath().
So, answer to your question, statement to put after creation of QApplication instance:
QSettings *settings = new QSettings(
QCoreApplication::applicationDirPath() + "/settings.ini",
QSettings::IniFormat,
qApp);
But, as noted in the comments under question, if you're making your program for general distribution, you should use the OS default. Examine all the constructors of QSettings to see what it can do. User does not often have write permission in the application directory. Note that you can also store settings to Windows registry with QSettings::NativeFormat.

Phonon::MediaSource, cannot use resource as media source

with QT 4.6, I am trying to access a wav file in my QResource file to use as the media source of a media player and it does not work:
Phonon::MediaObject *music;
music=Phonon::createPlayer(Phonon::MusicCategory,Phonon::MediaSource(:/FPS_sounds/arming.wav));
music->play();
If I put the direct path it works. I have been successful at using resources in other parts of my program so there does not seem to be a problem there and the Qt doc says I can use QResource for this type of operation. Is this a bug or am I missing something?
This one gave me a good scratch as well.
But lo and behold, it can be implemented easily using a temporary file:
{
QTemporaryFile f;
f.open();
QResource res(":/badger");
f.write((char*)res.data(),res.size());
f.flush();
f.setAutoRemove(true);
f.close();
QString fn = f.fileName();
QSound::play(fn);
}

Qt4.4 how to get the user settings path

linux: $HOME/.config
windows: %APPDATA%
mac os: $HOME/.config
It can be set using http://qt-project.org/doc/qt-4.8/qsettings.html#setPath, but it seems as I am not able to retrieve it.
http://qt-project.org/doc/qt-4.8/qlibraryinfo.html#location QLibraryInfo::LibrariesPath returns the system wide settings dir, which is not what I want.
Any ideas, or do I have to code it separately for each platform?
€: I want to create a sub directory, and store files into it. (You may punish me if this is a bad idea)
This might not answer your question directly: if you want to store per-user persistent data, shouldn't you use QDesktopServices::storageLocation(QDesktopServices::DataLocation) instead?
This is a nasty workaround. First you create QSettings, then get its location.
QSettings cfg(QSettings::IniFormat, QSettings::UserScope,
"organization", "application");
QString config_dir = QFileInfo(cfg.fileName()).absolutePath() + "/";
Credits go to the Qt Centre forum.
QSettings stores the default config in the user AppData directory. See documentation for QSettings. Also this code instructs to store the config in the Ini file format.
this works on both qt 4 and qt 5
QApplication::setApplicationName("MyApp");
QApplication::setOrganizationName("Me");
QString homePath;
#if QT_VERSION >= 0x050000
homePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
#else
homePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
#endif
Why do you need to know the settings path? If you are going to put settings in it, you could use QSettings. I could see making a subdirectory to hold various settings, but it seems like the easiest way would be to use QSettings directly.
As far as I can tell, you can't retrieve the path. In the Qt source, src/corelib/io/qsettings.cpp, there is a function to get the path:
static QString getPath(QSettings::Format format, QSettings::Scope scope)
{
...
but it's not accessible from code using Qt. You can't copy it and use it either, because it uses internal Qt globals to store the path...
EDIT: A solution was posted, using QDesktopServices.storageLocation(QDesktopServices.DataLocation) but it doesn't do exactly what the question was asking for, i.e. if I set a custom path using QSettings.setPath() it doesn't reflect the change.
What platform are you at?
Might be related or not but in windows, the default is to write QSettings to the registry.
I read more into the question than there was as it was originally posted. It is clearer after the edits. Ok, so can't you use..
QString QSettings::fileName () const
Returns the path where settings are written to using this QSettings object are stored.
On Windows, if the format is QSettings::NativeFormat, the return value is a system registry path, not a file path.