首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与文件一起使用qresource QFile

与文件一起使用qresource QFile
EN

Stack Overflow用户
提问于 2016-11-30 18:20:26
回答 3查看 1.1K关注 0票数 2

我有一个Qt项目,它有一组源文件/头文件,这些文件也用于其他不基于Qt的项目。这些文件处理.csv文件的读取(我将称之为CSVReader类)。CSVReader是在没有任何Qt特定函数调用的情况下编写的(我可以控制CSVReader的修改,但要求它不使用任何Qt特定的代码)。

在基于Qt的应用程序中,我喜欢使用.csv文件将这些额外的.qrc文件嵌入到.exe中,这样用户就不会意外地删除或修改这些文件。

显然,在读取这些数据时,这会造成问题,因为我的CSVReader使用fopenfread之类的调用。

我希望我可以在我的项目的Qt部分中使用类似以下内容(*),并将文件句柄传递给CSVReader。

代码语言:javascript
复制
QFile myFile("goforward.raw");
myFile.open(QIODevice::ReadOnly);
int fileHandle = myFile.handle();
FILE* fh = fdopen(fileHandle, "rb");

但是很明显,由于文件只存在于.exe中,所以对myFile.handle()的调用返回-1

我目前的想法(有点难看)是使用QFile打开文件,然后将文件写入硬盘,然后使用FILE *f = fopen(fname, "rt");将文件加载到CSVReader中,然后删除我编写的文件。

如果其他人对如何读取打开( qresource )有想法,我可以接受其他想法。

谢谢

EN

回答 3

Stack Overflow用户

发布于 2016-11-30 19:58:03

CSVReader可以做两件事中的任何一件:

  1. 从内存中解析--文件必须是内存--首先映射了。这在64位平台上是有意义的,在这些平台上,您不会耗尽虚拟内存。但在32位平台上,这并不是很灵活:您将无法在1G或2G上打开任何文件。CSVReader将处理一个const char *, size_t对。 请注意,内存映射与显式读取文件不同。当您内存映射一个文件时,读取是由操作系统代表您完成的:您从不亲自从文件中直接读取任何内容。 如果文件足够小,可以安装在32位平台上的虚拟内存中,或者如果您在64位平台上,这很可能是性能最好的方法,因为现代内核的页面映射系统在IO设备和解析器之间提供的阻抗不匹配最少。
  2. 使用抽象接口增量地从文件中读取数据。CSVReader将处理一个InputInterface实例。读者应该期待一个开放的接口实例。 读取器不应该打开文件本身,因为打开是特定于特定实现的。由于QFile-based实现将接受资源路径,而基于标准库的实现将不接受资源路径,因此使用通用open方法是没有意义的:它将隐藏通过构造而无法实现的错误。

第二种方法似乎具有最广泛的适用性。您可以按以下方式定义接口:

代码语言:javascript
复制
// https://github.com/KubaO/stackoverflown/tree/master/questions/file-interface-40895489
#include <cstdint>

class InputInterface {
protected:
   InputInterface() {}
public:
   virtual int64_t read(char *, int64_t maxSize) = 0;
   virtual int64_t pos() const = 0;
   virtual bool seek(int64_t) = 0;
   virtual bool isOpen() const = 0;
   virtual bool atEnd() const = 0;
   virtual bool ok() const = 0;
   virtual bool flush() = 0;
   virtual void close() = 0;
   virtual ~InputInterface() {}
};

QFile-based实现可以如下所示:

代码语言:javascript
复制
#include <QtCore>

class QtFile : public InputInterface {
   QFile f;
public:
   QtFile() {}
   QtFile(const QString &name) : f(name) {}
   bool open(const QString &name, QFile::OpenMode mode) {
      close();
      f.setFileName(name);
      return f.open(mode);
   }
   bool open(QFile::OpenMode mode) {
      close();
      return f.open(mode);
   }
   void close() override {
      f.close();
   }
   bool flush() override {
      return f.flush();
   }
   int64_t read(char * buf, int64_t maxSize) override {
      return f.read(buf, maxSize);
   }
   int64_t pos() const override {
      return f.pos();
   }
   bool seek(int64_t pos) override {
      return f.seek(pos);
   }
   bool isOpen() const override {
      return f.isOpen();
   }
   bool atEnd() const override {
      return f.atEnd();
   }
   bool ok() const override {
      return f.isOpen() && f.error() == QFile::NoError;
   }
   QString statusString() const {
      return f.errorString();
   }
};

普通的C++实现是:

代码语言:javascript
复制
#include <cstdio>
#include <cerrno>
#include <cassert>
#include <string>

class CFile : public InputInterface {
   FILE *f = nullptr;
   int mutable m_status = 0;
public:
   CFile() {}
   CFile(FILE * f) : f(f) {
      assert(!ferror(f)); // it is impossible to retrieve the error at this point
      m_status = 0;
   }
   ~CFile() { close(); }
   void close() override {
      if (f) fclose(f);
      f = nullptr;
      m_status = 0;
   }
   bool open(const char *name, const char *mode) {
      close();
      f = fopen(name, mode);
      if (!f) m_status = errno;
      return f;
   }
   bool flush() override {
      auto rc = fflush(f);
      if (rc) m_status = errno;
      return !rc;
   }
   bool isOpen() const override { return f; }
   bool atEnd() const override { return f && feof(f); }
   bool ok() const override { return f && !m_status; }
   int64_t read(char * buf, int64_t maxSize) override {
      auto n = fread(buf, 1, maxSize, f);
      if (ferror(f)) m_status = errno;
      return n;
   }
   bool seek(int64_t pos) override {
      auto rc = fseek(f, pos, SEEK_SET);
      if (rc) m_status = errno;
      return !rc;
   }
   int64_t pos() const override {
      if (!f) return 0;
      auto p = ftell(f);
      if (p == EOF) {
         m_status = errno;
         return 0;
      }
      return p;
   }
   std::string statusString() const {
      return {strerror(m_status)};
   }
};
票数 2
EN

Stack Overflow用户

发布于 2016-11-30 21:00:22

我选择了@Kuba的第一种方法,因为我的应用程序中没有内存限制。对于那些感兴趣的人,我在下面发布了我的普通C++和基于Qt的方法。

平原C++

代码语言:javascript
复制
std::ifstream ifs("file.csv");
std::string fileContents((std::istreambuf_iterator<char>(ifs)),
                         (std::istreambuf_iterator<char>()));
CSVReader csvReader(fileContents);

基于Qt

代码语言:javascript
复制
QFile qF(":/file.csv");
if (qF.open(QFile::ReadOnly))
{
    QTextStream qTS(&qF);
    CSVReader csvReader(qTS.readAll().toStdString());
}
票数 0
EN

Stack Overflow用户

发布于 2016-11-30 22:39:42

您可以利用Qt QTemporaryFile复制数据并启动。QTemporaryfile在每个操作系统上都能工作。

下面是一个示例(这个临时文件与整个qApp相关联,以便在退出应用程序后将其删除):

代码语言:javascript
复制
QTemporaryFile tmpFile(qApp);
tmpFile.setFileTemplate("XXXXXX.csv");
if (tmpFile.open()) {
    QString tmp_filename=tmpFile.fileName();
    qDebug() << "temporary" << tmp_filename;

    QFile file(":/file.csv");
    if (file.open(QIODevice::ReadOnly)) {
        tmpFile.write(file.readAll());
    }

    tmpFile.close();
}

可以重新打开文件tmpFile.fileName()

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40895489

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档