CSVReader
可以做以下两件事之一:
从内存解析 - 文件必须首先进行内存映射。这在不会耗尽虚拟内存的 64 位平台上是有意义的。但在 32 位平台上,这不是很灵活:您将无法打开任何超过 1 或 2 GB 大小的文件。CSVReader
可以解决一对const char *, size_t
。
请注意,内存映射与从文件中显式读取不同。当您对文件进行内存映射时,操作系统会代表您完成读取操作:您永远不会直接从文件中读取任何内容。
如果文件足够小以适合 32 位平台上的虚拟内存,或者如果您在 64 位平台上,这很可能是性能最佳的方法,因为现代内核的页面映射系统将提供最小的阻抗不匹配在 IO 设备和解析器之间。
使用抽象接口从文件中增量读取数据。CSVReader
可以解决一个实例InputInterface
。读者应该期待一个开放的接口实例。
读者不应该打开文件本身,因为打开是特定于特定实现的。由于QFile
基于 - 的实现将接受资源路径,而基于标准库的实现则不会,因此使用通用open
方法毫无意义:它将隐藏错误,否则无法通过构造实现。
第二种方法似乎具有最广泛的适用性。您可以按如下方式定义接口:
// 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)};
}
};