は、次の 2 つのCSVReader
いずれかを実行できます。
メモリから解析 - 最初にファイルをメモリマップする必要があります。これは、仮想メモリが不足しない 64 ビット プラットフォームでは理にかなっています。しかし、32 ビット プラットフォームでは、これはあまり柔軟ではありません。サイズが 1 ~ 2 ギガバイトを超えるファイルを開くことはできません。ペアCSVReader
で動作します。const char *, size_t
メモリ マッピングは、ファイルから明示的に読み取ることと同じではないことに注意してください。ファイルをメモリ マップすると、オペレーティング システムがユーザーに代わって読み取りを行います。ファイルから直接読み取りを行うことはありません。
ファイルが 32 ビット プラットフォームの仮想メモリに収まるほど小さい場合、または 64 ビット プラットフォームを使用している場合、最新のカーネルのページ マッピング システムが最小のインピーダンス ミスマッチを提供するため、これが最もパフォーマンスの高い方法になります。 IO デバイスとパーサーの間。
抽象インターフェイスを使用して、ファイルからデータを段階的に読み取ります。はインスタンスCSVReader
で機能しInputInterface
ます。リーダーは、インターフェイスのインスタンスが開いていることを期待する必要があります。
開くことは特定の実装に固有であるため、リーダーはファイル自体を開くべきではありません。QFile
ベースの実装はリソース パスを受け入れますが、標準のライブラリ ベースの実装は受け入れないため、ジェネリック メソッドを使用しても意味がありませopen
ん。それ以外の場合は構造上不可能なエラーが隠されます。
2 番目のアプローチは、適用範囲が広いようです。次のようにインターフェイスを定義できます。
// 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)};
}
};