13,032
回編集
| 560行目: | 560行目: | ||
qDebug() << "CSVファイルの書き込みに成功"; | qDebug() << "CSVファイルの書き込みに成功"; | ||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 分割処理を使用したCSVファイルの読み込み == | |||
以下の例では、RFC4180に準拠したCSVファイルを分割読み込みしている。<br> | |||
分割処理は、大規模なCSVファイルを効率的に処理する場合に特に有効である。<br> | |||
<br> | |||
* 分割読み込み | |||
*: ファイルを1度に全て読み込むのではなく、指定されたチャンクサイズごとに読み込む。 | |||
*: これにより、大規模なファイルでもメモリ使用量を抑えることができる。 | |||
* 行番号の追跡 | |||
*: 各レコード番号を追跡して、コールバック関数に渡す。 | |||
*: これにより、エラーが発生した場合に正確な位置を特定することができる。 | |||
<br> | |||
<u>※注意</u><br> | |||
<u>チャンクサイズの選択はパフォーマンスに影響を与える可能性がある。</u><br> | |||
<u>適切なサイズは使用環境やファイルサイズによって異なる場合がある。</u><br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QFile> | |||
#include <QTextStream> | |||
#include <functional> | |||
#include <QDebug> | |||
enum class CSVError { | |||
NoError, | |||
FileOpenError, | |||
ReadError, | |||
ParseError | |||
}; | |||
class CSVReader | |||
{ | |||
private: | |||
QString m_filename; | |||
qint64 m_chunkSize; | |||
private: | |||
QStringList parseLine(const QString &line) | |||
{ | |||
QStringList fields; | |||
QString field; | |||
bool inQuotes = false; | |||
for (int i = 0; i < line.length(); i++) { | |||
if (line[i] == '"') { | |||
if (inQuotes && i + 1 < line.length() && line[i + 1] == '"') { | |||
field += '"'; | |||
i++; | |||
} | |||
else { | |||
inQuotes = !inQuotes; | |||
} | |||
} | |||
else if (line[i] == ',' && !inQuotes) { | |||
fields.append(field); | |||
field.clear(); | |||
} | |||
else { | |||
field += line[i]; | |||
} | |||
} | |||
fields.append(field); | |||
return fields; | |||
} | |||
public: | |||
CSVReader(const QString &filename, qint64 chunkSize = 1024 * 1024) : m_filename(filename), m_chunkSize(chunkSize) {} | |||
CSVError readCSV(std::function<bool(const QStringList&, qint64)> rowCallback) | |||
{ | |||
QFile file(m_filename); | |||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | |||
qDebug() << "ファイルのオープンに失敗: " << m_filename; | |||
return CSVError::FileOpenError; | |||
} | |||
QTextStream in(&file); | |||
in.setCodec("UTF-8"); | |||
QString buffer; | |||
QString remainder; | |||
qint64 lineNumber = 0; | |||
bool inQuotes = false; | |||
while (!in.atEnd()) { | |||
buffer = remainder + in.read(m_chunkSize); | |||
remainder.clear(); | |||
int start = 0; | |||
for (int i = 0; i < buffer.length(); i++) { | |||
if (buffer[i] == '"') { | |||
inQuotes = !inQuotes; | |||
} | |||
else if (buffer[i] == '\n' && !inQuotes) { | |||
QString line = buffer.mid(start, i - start); | |||
QStringList fields = parseLine(line); | |||
if (fields.isEmpty() && !line.isEmpty()) { | |||
qDebug() << "パースエラー: 行" << lineNumber + 1; | |||
return CSVError::ParseError; | |||
} | |||
if (!rowCallback(fields, lineNumber)) { | |||
// ユーザが処理を中断した場合 | |||
return CSVError::NoError; | |||
} | |||
start = i + 1; | |||
lineNumber++; | |||
} | |||
} | |||
remainder = buffer.mid(start); | |||
} | |||
if (!remainder.isEmpty()) { | |||
QStringList fields = parseLine(remainder); | |||
if (!fields.isEmpty()) { | |||
if (!rowCallback(fields, lineNumber)) { | |||
// ユーザが処理を中断した場合 | |||
return CSVError::NoError; | |||
} | |||
} | |||
else if (!remainder.trimmed().isEmpty()) { | |||
qDebug() << "パースエラー: 最終行"; | |||
return CSVError::ParseError; | |||
} | |||
} | |||
if (inQuotes) { | |||
qDebug() << "パースエラー: 閉じていない引用符があります"; | |||
return CSVError::ParseError; | |||
} | |||
return CSVError::NoError; | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
int main() | |||
{ | |||
CSVReader reader("example.csv"); | |||
CSVError error = reader.readCSV([](const QStringList& row, qint64 lineNumber) { | |||
qDebug() << "行" << lineNumber + 1 << ":" << row; | |||
// 例: 100行まで読み込みして中断 | |||
if (lineNumber >= 99) { | |||
qDebug() << "100行読み込んだので中断します"; | |||
return false; | |||
} | |||
return true; // 続けて読み込む | |||
}); | |||
switch (error) { | |||
case CSVError::NoError: | |||
qDebug() << "CSVファイルの読み込みに成功"; | |||
break; | |||
case CSVError::FileOpenError: | |||
qDebug() << "ファイルのオープンに失敗"; | |||
break; | |||
case CSVError::ReadError: | |||
qDebug() << "ファイルの読み込み中にエラーが発生"; | |||
break; | |||
case CSVError::ParseError: | |||
qDebug() << "CSVのパース中にエラーが発生"; | |||
break; | |||
} | |||
return 0; | return 0; | ||