Qt 无法打开QFile进行追加/读写

Qt 无法打开QFile进行追加/读写,qt,qfile,Qt,Qfile,我正在尝试使用以下代码打开现有文件以在其末尾追加数据: void AddPharmacyForm::addInsertToFile(QString insert) { QFile inserts(":/new/prefix1/insertstatements.txt"); if(!inserts.exists()) qDebug() << "File does not exist"; if(inserts.isOpen())

我正在尝试使用以下代码打开现有文件以在其末尾追加数据:

void AddPharmacyForm::addInsertToFile(QString insert)
{
    QFile inserts(":/new/prefix1/insertstatements.txt");

    if(!inserts.exists())
        qDebug() << "File does not exist";

    if(inserts.isOpen())
        qDebug() << "file is open";

    if(inserts.open(QFile::ReadWrite | QFile::Text))
    {
        // Another workaround- could not open file with append flag
        qDebug() << "im here!";

        QString currentInserts;
        QTextStream out(&inserts);

        out >> currentInserts;
        out << endl << insert;

        inserts.close();
    }
    else
    {
        QMessageBox::information(this, tr("Error"), tr("Cannot add new pharmacy! "
                                                       "Please contact program designer."
                                                        ));

        qDebug() << "error code: " + QString::number(inserts.error());

        return;
    }
}
它不会通知文件不存在和文件正在打开。我还尝试使用不同的标志打开文件:QFile::ReadWrite、QFile::append、QFile::WriteOnly和QIODevice中的相同模式。错误代码仍然相同。当我从另一个类打开文件时,该文件打开时没有错误(这不是访问错误)

是什么导致了这个问题?

当您使用(qrc文件)为您的项目添加文件时,它们会被直接编译成应用程序的二进制文件,因此是只读的。如文件所述:-

可以将资源数据编译成二进制,从而在应用程序代码中立即访问,也可以创建二进制资源,稍后在资源系统注册的应用程序代码中访问

而且

目前,Qt总是将数据直接存储在可执行文件中,即使在Windows、macOS和iOS上,操作系统都提供了对资源的本机支持。这可能会在未来的Qt版本中发生变化

当您使用(qrc文件)为您的项目添加文件时,它们将直接编译为应用程序的二进制文件,因此是只读的。如文件所述:-

可以将资源数据编译成二进制,从而在应用程序代码中立即访问,也可以创建二进制资源,稍后在资源系统注册的应用程序代码中访问

而且

目前,Qt总是将数据直接存储在可执行文件中,即使在Windows、macOS和iOS上,操作系统都提供了对资源的本机支持。这可能会在未来的Qt版本中发生变化


不支持写入资源系统,无论是使用Qt的资源系统实现还是平台本机实现。您的应用程序通常无权修改其自身的可执行文件、应用程序包或其安装位置—如果这样做,则会带来安全风险,因为网络代码中的错误很容易被利用,从而感染用户的系统。所以你想做的只是个坏主意

相反,将修改后的资源存储在应用程序的数据文件夹中,如果文件不存在,则恢复为从资源中读取。如果文件很小,附加到文件中也可能不是很明智:这样的附加不是原子的,可能会部分失败,导致文件损坏。使用
QSaveFile
可以保证完全成功,也可以在不修改任何数据的情况下失败

下面是一个示例实现。关闭代码时,不需要关闭代码,因为<代码> > QueFix/Cord>将自动关闭,因为它是一个管理C++类的合适资源。通过更早地关闭它,我们确保了对文件描述符(一种有限的系统资源)的最小使用

// https://github.com/KubaO/stackoverflown/tree/master/questions/resource-bypass-43044268
#include <QtCore>

const char kInsertsFile[] = ":/insertstatements.txt";

QString toWritableName(const QString & qrcFileName) {
   Q_ASSERT (qrcFileName.startsWith(":/"));
   QFileInfo info(qrcFileName);
   return
         QStandardPaths::writableLocation(QStandardPaths::DataLocation)
         + info.path().mid(1) + '/' + info.fileName();
}

QString toReadableName(const QString & qrcFileName) {
   Q_ASSERT (qrcFileName.startsWith(":/"));
   auto writable = toWritableName(qrcFileName);
   return QFileInfo(writable).exists() ? writable : qrcFileName;
}

bool setupWritableFile(QSaveFile & dst, QIODevice::OpenMode mode = {}) {
   Q_ASSERT (dst.fileName().startsWith(":/"));
   Q_ASSERT (mode == QIODevice::OpenMode{} || mode == QIODevice::Text);
   QFile src(toReadableName(dst.fileName()));
   dst.setFileName(toWritableName(dst.fileName()));
   if (!src.open(QIODevice::ReadOnly | mode))
      return false;
   auto data = src.readAll();
   src.close(); // Don't keep the file descriptor tied up any longer.
   QFileInfo dstInfo(dst.fileName());
   if (!dstInfo.dir().exists() && !QDir().mkpath(dstInfo.path()))
      return false;
   if (!dst.open(QIODevice::WriteOnly | mode))
      return false;
   return dst.write(data) == data.size();
}

bool addInsertToFile(const QString & insert) {
   QSaveFile file(kInsertsFile);
   if (!setupWritableFile(file, QIODevice::Text))
      return false;
   if (true) {
      // Alternative 1
      QTextStream s(&file);
      s << insert << '\n';
   } else {
      // Alternative 2
      file.write((insert + '\n').toLocal8Bit());
   }
   return file.commit();
}

QStringList readInserts() {
   QFile file(toReadableName(kInsertsFile));
   if (!file.open(QIODevice::ReadOnly))
      return {};
   return QString::fromLocal8Bit(file.readAll()).split('\n', QString::SkipEmptyParts);
}

int main(int argc, char ** argv) {
   QCoreApplication app{argc, argv};
   app.setApplicationName("resource-bypass-42044268");
   qDebug() << "Original Inserts:" << readInserts();
   auto rc = addInsertToFile("NewInsert");
   qDebug() << "Modification status:" << rc;
   qDebug() << "Current Inserts:" << readInserts();
}
//https://github.com/KubaO/stackoverflown/tree/master/questions/resource-bypass-43044268
#包括
const char kInsertsFile[]=“:/insertstatements.txt”;
QString到ritablename(常量QString和qrcFileName){
Q_ASSERT(qrcFileName.startsWith(“:/”);
QFileInfo信息(qrcFileName);
回来
QStandardPath::writableLocation(QStandardPath::DataLocation)
+info.path().mid(1)+'/'+info.fileName();
}
QString-toReadableName(常量QString&qrcFileName){
Q_ASSERT(qrcFileName.startsWith(“:/”);
自动可写=toWritableName(qrcFileName);
返回QFileInfo(可写).exists()?可写:qrcFileName;
}
bool setupwriteblefile(QSaveFile&dst,QIODevice::OpenMode={}){
Q_ASSERT(dst.fileName().startsWith(“:/”);
Q|u ASSERT(mode==QIODevice::OpenMode{}| | mode==QIODevice::Text);
QFile src(toReadableName(dst.fileName());
setFileName(toWritableName(dst.fileName());
如果(!src.open(QIODevice::ReadOnly | mode))
返回false;
自动数据=src.readAll();
src.close();//不要再将文件描述符绑定起来。
QFileInfo-dstInfo(dst.fileName());
如果(!dstInfo.dir()
返回false;
如果(!dst.open(QIODevice::WriteOnly |模式))
返回false;
返回dst.write(data)=data.size();
}
bool addInsertToFile(常量字符串和插入){
QSaveFile文件(kInsertsFile);
如果(!setupWritableFile(file,QIODevice::Text))
返回false;
如果(真){
//备选案文1
QTextStream(文件(&F);

s不支持写入资源系统,无论是使用Qt的资源系统实现还是平台本机实现。您的应用程序通常无权修改其自身的可执行文件、应用程序包或其安装位置-如果这样做,则会带来安全风险,因为网络代码中的错误可能很容易爆发它会感染你的用户系统,所以你想做的只是一个坏主意

相反,将修改后的资源存储在应用程序的数据文件夹中,如果文件不存在,则恢复到从资源中读取。如果文件很小,则附加到文件也可能不是非常明智的做法:这样的附加不是原子的,可能会部分失败,导致文件损坏。使用
QSaveFile
可以保证在不修改任何数据的情况下完全成功或失败

一个示例实现。不必关闭文件,因为<代码> qfile <代码>将自动关闭,因为它是一个合适的资源管理C++类。通过更早的关闭,我们可以确保文件描述符的最小使用——一个有限的系统资源。

// https://github.com/KubaO/stackoverflown/tree/master/questions/resource-bypass-43044268
#include <QtCore>

const char kInsertsFile[] = ":/insertstatements.txt";

QString toWritableName(const QString & qrcFileName) {
   Q_ASSERT (qrcFileName.startsWith(":/"));
   QFileInfo info(qrcFileName);
   return
         QStandardPaths::writableLocation(QStandardPaths::DataLocation)
         + info.path().mid(1) + '/' + info.fileName();
}

QString toReadableName(const QString & qrcFileName) {
   Q_ASSERT (qrcFileName.startsWith(":/"));
   auto writable = toWritableName(qrcFileName);
   return QFileInfo(writable).exists() ? writable : qrcFileName;
}

bool setupWritableFile(QSaveFile & dst, QIODevice::OpenMode mode = {}) {
   Q_ASSERT (dst.fileName().startsWith(":/"));
   Q_ASSERT (mode == QIODevice::OpenMode{} || mode == QIODevice::Text);
   QFile src(toReadableName(dst.fileName()));
   dst.setFileName(toWritableName(dst.fileName()));
   if (!src.open(QIODevice::ReadOnly | mode))
      return false;
   auto data = src.readAll();
   src.close(); // Don't keep the file descriptor tied up any longer.
   QFileInfo dstInfo(dst.fileName());
   if (!dstInfo.dir().exists() && !QDir().mkpath(dstInfo.path()))
      return false;
   if (!dst.open(QIODevice::WriteOnly | mode))
      return false;
   return dst.write(data) == data.size();
}

bool addInsertToFile(const QString & insert) {
   QSaveFile file(kInsertsFile);
   if (!setupWritableFile(file, QIODevice::Text))
      return false;
   if (true) {
      // Alternative 1
      QTextStream s(&file);
      s << insert << '\n';
   } else {
      // Alternative 2
      file.write((insert + '\n').toLocal8Bit());
   }
   return file.commit();
}

QStringList readInserts() {
   QFile file(toReadableName(kInsertsFile));
   if (!file.open(QIODevice::ReadOnly))
      return {};
   return QString::fromLocal8Bit(file.readAll()).split('\n', QString::SkipEmptyParts);
}

int main(int argc, char ** argv) {
   QCoreApplication app{argc, argv};
   app.setApplicationName("resource-bypass-42044268");
   qDebug() << "Original Inserts:" << readInserts();
   auto rc = addInsertToFile("NewInsert");
   qDebug() << "Modification status:" << rc;
   qDebug() << "Current Inserts:" << readInserts();
}
//https://github.com/KubaO/stackoverflown/tree/master/questions/resource-bypass-43044268
#包括
const char kInsertsFile[]=“:/insertstatements.txt”;
QString到ritablename(常量QString和qrcFileName){
Q_ASSERT(qrcFileName.startsWith(“:/”);
QFileInfo信息(qrcFile