gpt4 book ai didi

c++ - 将 qresource QFile 与 FILE 一起使用

转载 作者:搜寻专家 更新时间:2023-10-31 02:13:45 26 4
gpt4 key购买 nike

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

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

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

我希望我可以在我的项目的 Qt 部分使用类似下面的东西 ( Convert QFile to FILE* ) 并将文件句柄传递给 CSVReader。

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 ");,然后删除我写的文件。

如果其他人对如何阅读打开 qresource 文件有任何想法,我愿意接受其他想法。

谢谢

最佳答案

CSVReader 可以做两件事之一:

  1. 从内存解析 - 文件必须首先进行内存映射。这在不会耗尽虚拟内存的 64 位平台上很有意义。但在 32 位平台上,这不是很灵活:您将无法打开任何大小超过 1 GB 或 2 GB 的文件。 CSVReader 可以处理 const char *, size_t 对。

    请注意,内存映射与从文件中显式读取不同。当您对文件进行内存映射时,读取由操作系统代表您完成:您永远不会自己直接从文件中进行任何读取。

    如果文件足够小以适合 32 位平台上的虚拟内存,或者如果您在 64 位平台上,这很可能是性能最佳的方法,因为现代内核的页面映射系统将提供IO 设备和解析器之间的最小阻抗不匹配。

  2. 使用抽象接口(interface)从文件中增量读取数据。 CSVReader 将使用 InputInterface 实例。读者应该期待一个开放的接口(interface)实例。

    读者不应打开文件本身,因为打开是特定于特定实现的。由于基于 QFile 的实现将接受资源路径,而基于标准库的实现则不会,因此使用通用的 open 方法是没有意义的:它将隐藏错误否则无法通过构造实现。

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

// 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 的实现可能如下所示:

#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++ 实现是:

#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)};
}
};

关于c++ - 将 qresource QFile 与 FILE 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40895489/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com