「Qtの基礎 - CSVファイル」の版間の差分
(→概要) |
|||
| 108行目: | 108行目: | ||
File.close(); | File.close(); | ||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== CSVファイル (RFC4180準拠) の読み込み == | |||
RFC4180は、CSVファイルの標準的な形式を定義しており、これに従うことで互換性の高いCSV処理が可能になる。<br> | |||
<br> | |||
以下の例では、RFC4180の規則に従ってCSVファイルを読み込んでいる。<br> | |||
* ダブルクォートで囲まれたフィールド内のカンマと改行を正しく処理する。 | |||
* フィールド内の二重引用符 ("") を単一の引用符 ('') として解釈する。 | |||
* 各行の末尾の空白を除去する。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QFile> | |||
#include <QTextStream> | |||
#include <QStringList> | |||
#include <QDebug> | |||
QList<QStringList> readCSV(const QString &filename) | |||
{ | |||
QList<QStringList> result; | |||
QFile file(filename); | |||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | |||
qDebug() << "ファイルを開けません:" << filename; | |||
return result; | |||
} | |||
QTextStream in(&file); | |||
in.setCodec("UTF-8"); | |||
QString line; | |||
QStringList fields; | |||
bool inQuotes = false; | |||
QString field; | |||
while (!in.atEnd()) { | |||
QChar ch; | |||
in >> ch; | |||
if (inQuotes) { | |||
if (ch == '"') { | |||
if (in.peek() == '"') { | |||
field += ch; | |||
in >> ch; // 次の文字(二重引用符)を読み飛ばす | |||
} | |||
else { | |||
inQuotes = false; | |||
} | |||
} | |||
else { | |||
field += ch; | |||
} | |||
} | |||
else { | |||
if (ch == '"') { | |||
inQuotes = true; | |||
} | |||
else if (ch == ',' || ch == '\n' || in.atEnd()) { | |||
fields.append(field.trimmed()); | |||
field.clear(); | |||
if (ch == '\n' || in.atEnd()) { | |||
result.append(fields); | |||
fields.clear(); | |||
} | |||
} | |||
else { | |||
field += ch; | |||
} | |||
} | |||
} | |||
file.close(); | |||
return result; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== CSVファイル (RFC4180準拠) の書き込み == | |||
RFC4180は、CSVファイルの標準的な形式を定義しており、これに従うことで互換性の高いCSV処理が可能になる。<br> | |||
<br> | |||
以下の例では、RFC4180の規則に従ってCSVファイルを書き込んでいる。<br> | |||
* カンマ、引用符、改行を含むフィールドを適切にダブルクォートで囲む。 | |||
* フィールド内の引用符を二重引用符 ("") にエスケープする。 | |||
* 各行の終わりに改行を挿入する。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QFile> | |||
#include <QTextStream> | |||
#include <QStringList> | |||
#include <QDebug> | |||
bool writeCSV(const QString &filename, const QList<QStringList> &data) | |||
{ | |||
QFile file(filename); | |||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { | |||
qDebug() << "ファイルを開けません:" << filename; | |||
return false; | |||
} | |||
QTextStream out(&file); | |||
out.setCodec("UTF-8"); | |||
for (const QStringList &row : data) { | |||
for (int i = 0; i < row.size(); ++i) { | |||
QString field = row[i]; | |||
bool needQuotes = field.contains(QRegExp("[,\"\n\r]")); | |||
if (needQuotes) { | |||
out << '"' << field.replace("\"", "\"\"") << '"'; | |||
} | |||
else { | |||
out << field; | |||
} | |||
if (i < row.size() - 1) { | |||
out << ","; | |||
} | |||
} | |||
out << "\n"; | |||
} | |||
file.close(); | |||
return true; | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
2024年9月7日 (土) 13:38時点における版
概要
CSV (Comma-Separated Values) ファイルは、テキストベースのデータ形式である。
各行がデータレコードを表しており、フィールドはカンマで区切られている。
Qtでは、CSVファイルの読み書きを簡単に行うことができる。
主にQFileクラス、QTextStreamクラス、QStringListを使用してCSVファイルを操作する。
QFileクラスはファイルのオープン・クローズを行い、QTextStreamクラスはテキストの読み書きを行う。
QStringListクラスは、CSVの各行を分割して扱う場合に便利である。
ファイルの読み込み時は、QFileオブジェクトでファイルを開き、QTextStreamオブジェクトを使用して1行ずつ読み込む。
各レコードは、QString::splitメソッドでフィールドに分割することができる。
書き込み時も同様、QFileオブジェクトとQTextStreamオブジェクトを使用する。
データをカンマで連結して、QTextStreamクラスの<<演算子を使用して書き込む。
また、ファイルがオープンできない、書き込むことができない等の状況に対応するため、適切な例外処理やエラー処理を実装することが推奨される。
なお、CSVファイルの形式が統一されていない場合 (例: フィールド内にカンマが含まれる)、パースが複雑になることがある。
このような場合は、正規表現やより高度なパーシング技術が必要になることもある。
CSVファイル
以下の例では、CSVファイルを作成している。
処理の流れを以下に示す。
- 数値データを生成する。
ここでは、sin曲線である を生成する。 - 数値データをテキストデータに変換する。
- ファイル保存ダイアログを開いて、保存するファイル名を入力する。
- 全テキストデータを書き込む。
#include <QFileDialog>
#include <QMessageBox>
#include <QTextStream>
#include <QFile>
#include <vector>
#include <math.h>
#include <sstream>
#include "mainwindow.h"
#include "ui_mainwindow.h"
using namespace std;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::OnButtonClicked()
{
// Input File Name
QString FileName = QFileDialog::getSaveFileName(this, tr("Save CSV File"), "", tr("CSV (*.csv);;All Files (*)"));
if(FileName.isEmpty())
{ // Cancel
return;
}
// Generate CSV Data
int iSize = 100;
vector<double> lx(iSize, 0.0f),
ly(iSize, 0.0f);
double dx = 2 * 3.15159 / iSize;
for(int i = 0; i < iSize; i++)
{
lx[i] = i * dx;
ly[i] = sin(vx);
}
// Convert from Double to String
QString strFileData = "";
//stringstream ss;
for(int i = 0; i < iSize; i++)
{
strFileData += lx[i] + ", " + ly[i] + "\n";
//ss << lx[i] << "," << ly[i] << endl;
}
// Write to File
QFile File(FileName);
if(!File.open(QIODevice::WriteOnly))
{
QMessageBox::information(this, tr("Unable to open file"), File.errorString());
return;
}
QTextStream OutStream(&File);
// 浮動小数点をe形式にする
//OutStream.setRealNumberNotation(QTextStream::ScientificNotation);
// 浮動小数点の桁数を固定
//OutStream.setRealNumberNotation(QTextStream::FixedNotation);
// 浮動小数点の桁数を設定
OutStream.setRealNumberPrecision(3);
OutStream << strFileData;
//OutStream << ss.str().c_str();
File.close();
}
CSVファイル (RFC4180準拠) の読み込み
RFC4180は、CSVファイルの標準的な形式を定義しており、これに従うことで互換性の高いCSV処理が可能になる。
以下の例では、RFC4180の規則に従ってCSVファイルを読み込んでいる。
- ダブルクォートで囲まれたフィールド内のカンマと改行を正しく処理する。
- フィールド内の二重引用符 ("") を単一の引用符 () として解釈する。
- 各行の末尾の空白を除去する。
#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QDebug>
QList<QStringList> readCSV(const QString &filename)
{
QList<QStringList> result;
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "ファイルを開けません:" << filename;
return result;
}
QTextStream in(&file);
in.setCodec("UTF-8");
QString line;
QStringList fields;
bool inQuotes = false;
QString field;
while (!in.atEnd()) {
QChar ch;
in >> ch;
if (inQuotes) {
if (ch == '"') {
if (in.peek() == '"') {
field += ch;
in >> ch; // 次の文字(二重引用符)を読み飛ばす
}
else {
inQuotes = false;
}
}
else {
field += ch;
}
}
else {
if (ch == '"') {
inQuotes = true;
}
else if (ch == ',' || ch == '\n' || in.atEnd()) {
fields.append(field.trimmed());
field.clear();
if (ch == '\n' || in.atEnd()) {
result.append(fields);
fields.clear();
}
}
else {
field += ch;
}
}
}
file.close();
return result;
}
CSVファイル (RFC4180準拠) の書き込み
RFC4180は、CSVファイルの標準的な形式を定義しており、これに従うことで互換性の高いCSV処理が可能になる。
以下の例では、RFC4180の規則に従ってCSVファイルを書き込んでいる。
- カンマ、引用符、改行を含むフィールドを適切にダブルクォートで囲む。
- フィールド内の引用符を二重引用符 ("") にエスケープする。
- 各行の終わりに改行を挿入する。
#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QDebug>
bool writeCSV(const QString &filename, const QList<QStringList> &data)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "ファイルを開けません:" << filename;
return false;
}
QTextStream out(&file);
out.setCodec("UTF-8");
for (const QStringList &row : data) {
for (int i = 0; i < row.size(); ++i) {
QString field = row[i];
bool needQuotes = field.contains(QRegExp("[,\"\n\r]"));
if (needQuotes) {
out << '"' << field.replace("\"", "\"\"") << '"';
}
else {
out << field;
}
if (i < row.size() - 1) {
out << ",";
}
}
out << "\n";
}
file.close();
return true;
}