QFile in AppDataLocation not readable/writeable
-
I am unable to read from or write to a file in QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) under Android - and I don't have a clue, why.
Isn't AppDataLocation supposed to be inside the sandbox, allowing me to access my files?Am I mistaken? Is there any better location to use?
Or am I doing anything very stupid here?This is my code:
auto appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); auto fileName = appDataPath + QStringLiteral("/products.json"); QFile saveFile(fileName); saveFile.setPermissions(QFileDevice::ReadOther|QFileDevice::WriteOther); qDebug()<<"fileName: "<<fileName; qDebug()<<"saveFile.exists(): "<<saveFile.exists(); qDebug()<<"saveFile.isOpen(): "<<saveFile.isOpen(); qDebug()<<"saveFile.isReadable(): "<<saveFile.isReadable(); qDebug()<<"saveFile.isWritable(): "<<saveFile.isWritable(); qDebug()<<"saveFile.errorString() before: "<<saveFile.errorString(); if (!saveFile.open(QIODevice::ReadWrite)) { qWarning("Couldn't open products file."); qDebug()<<"saveFile.errorString() after: "<<saveFile.errorString(); return false; } saveFile.write(QJsonDocument(saveProductsObj).toJson(QJsonDocument::Indented)); saveFile.close(); return true;
This is my output:
fileName: "/data/user/0/de.herrdiel.punktlandung/files/products.json" saveFile.exists(): true saveFile.isOpen(): false saveFile.isReadable(): false saveFile.isWritable(): false saveFile.errorString() before: "Unknown error" Couldn't open products file. saveFile.errorString() after: "Permission denied"
-
I am unable to read from or write to a file in QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) under Android - and I don't have a clue, why.
Isn't AppDataLocation supposed to be inside the sandbox, allowing me to access my files?Am I mistaken? Is there any better location to use?
Or am I doing anything very stupid here?This is my code:
auto appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); auto fileName = appDataPath + QStringLiteral("/products.json"); QFile saveFile(fileName); saveFile.setPermissions(QFileDevice::ReadOther|QFileDevice::WriteOther); qDebug()<<"fileName: "<<fileName; qDebug()<<"saveFile.exists(): "<<saveFile.exists(); qDebug()<<"saveFile.isOpen(): "<<saveFile.isOpen(); qDebug()<<"saveFile.isReadable(): "<<saveFile.isReadable(); qDebug()<<"saveFile.isWritable(): "<<saveFile.isWritable(); qDebug()<<"saveFile.errorString() before: "<<saveFile.errorString(); if (!saveFile.open(QIODevice::ReadWrite)) { qWarning("Couldn't open products file."); qDebug()<<"saveFile.errorString() after: "<<saveFile.errorString(); return false; } saveFile.write(QJsonDocument(saveProductsObj).toJson(QJsonDocument::Indented)); saveFile.close(); return true;
This is my output:
fileName: "/data/user/0/de.herrdiel.punktlandung/files/products.json" saveFile.exists(): true saveFile.isOpen(): false saveFile.isReadable(): false saveFile.isWritable(): false saveFile.errorString() before: "Unknown error" Couldn't open products file. saveFile.errorString() after: "Permission denied"
-
Hi @J-Hilk, thanks for your input!
You've said in QFile in AppDataLocation not readable/writeable:on mobile you'll have to mkDir the path first, because the directory doesn't exist yet
The directory does exist for sure, though, because the file does exist there already:
saveFile.exists(): true
Interesting catch from just now: removing the file does work, afterwards writing (to non-existing file) works, thus re-creating the removed file.
This workaround actually removes my problem, but not my questions. Partly dumb questions, perhaps:
- Do I have to remove a file before just overwriting it?
- Why isn't the existing file marked as readable? -
Hi,
Did you check the permissions right after finishing the write to the file and having closed it ?
-
Thank you for yor time @SGaist! You've said in QFile in AppDataLocation not readable/writeable:
Did you check the permissions right after finishing the write to the file and having closed it ?
Now this is interesting. "Normally", after writing it, the file has these permissions:
- QFileDevice::WriteUser 0x0200: The file is writable by the user.
- QFileDevice::ReadUser 0x0400: The file is readable by the user.
- QFileDevice::WriteOwner 0x2000: The file is writable by the owner of the file.
- QFileDevice::ReadOwner 0x4000: The file is readable by the owner of the file.
I've just realized, that the problem only seems to occur after importing the file from outside the application. After import, it has the permissions:
- QFileDevice::ReadOther 0x0004 The file is readable by anyone.
- QFileDevice::ReadGroup 0x0040 The file is readable by the group.
- QFileDevice::ReadUser 0x0400 The file is readable by the user.
- QFileDevice::ReadOwner 0x4000 The file is readable by the owner of the file.
In spite of that, I can still remove it!
I now set more specific permissions to the file:
saveFile.setPermissions(QFlags<QFileDevice::Permission>( QFileDevice::WriteUser | QFileDevice::ReadUser | QFileDevice::WriteOwner | QFileDevice::ReadOwner));
Additionally I still remove and re-write as explained above.
I've yet to see the problem again. Seems to work.Would you regard first removing and then re-writing the file as a somewhat clean or recommendable solution?
-
How are you importing it ?
-
I get the location with QML FileDialog (importing QtQuick.Dialogs 1.3)
FileDialog { id: importProductFileDialog title: "Choose new product file" folder: shortcuts.home onAccepted: { var result = controller.importGenericList(importProductFileDialog.fileUrl) } }
My import is done then from c++ controller class, specifically with this line:
newFile.copy(QStringLiteral("products.json")
The full method:
bool Controller::importGenericList(QString fileUrl) { #ifndef Q_OS_ANDROID fileUrl = QUrl(fileUrl).toLocalFile(); #endif QFile newFile(fileUrl); QFile oldFile(QStringLiteral("products.json")); QFile backupFile(QStringLiteral("productsOLD.json")); // first we check if the new file is parseable ProductTableModel* testModel = new ProductTableModel(); bool isValidFile = testModel->readDataFromFile(newFile.fileName()); testModel->deleteLater(); if (!isValidFile) { qDebug()<<"not valid!"; return false; } // remove an old backup (if applicable) backupFile.remove(); // make a backup of our product list oldFile.copy(backupFile.fileName()); // NO check for backup success, as there may have been no products file in the first place. // delete our product list. oldFile.remove(); // try copying if (!newFile.copy(QStringLiteral("products.json"))) { // not successful? try to repair: QFile rescueFile("productsOLD.json"); rescueFile.copy(QStringLiteral("products.json")); return false; } auto model = qobject_cast<ProductTableModel*>(m_productModel->sourceModel()); if (!model) { qWarning()<<"product model could not be found!"; Q_ASSERT(model); return false; } // read the new file into the our actual model model->readDataFromFile(); m_productModel->setSortRole(Qt::UserRole +3); m_productModel->invalidate(); return true; }
-
Ok, then what about the permissions of the source file ? Here may be the issue.
-
@SGaist said in QFile in AppDataLocation not readable/writeable:
Here may be the issue.
And there, indeed, it was.
After import, settingfile.setPermissions(QFileDevice::WriteUser|QFileDevice::ReadUser|QFileDevice::WriteOwner|QFileDevice::ReadOwner);
does the trick.
Thank you very much, @J-Hilk and @SGaist!