13,046
回編集
| 360行目: | 360行目: | ||
break; | break; | ||
} | } | ||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== ストリーミング処理を使用したCSVファイルの書き込み == | |||
以下の例では、ストリーミング処理およびQtConcurrentを使用して非同期でCSVファイルを書き込みしている。<br> | |||
<br> | |||
* ストリーミング処理 | |||
*: QTextStreamクラスを使用して、データを逐次的に書き込む。 | |||
*: これにより、大規模なデータセットでもメモリ使用量を抑えることができる。 | |||
* 非同期処理 | |||
*: 書き込み処理をバックグラウンドで行うことにより、メインスレッドのブロッキングを防ぎ、アプリケーションの応答性を向上させることができる。 | |||
* キューイング | |||
*: enqueueRowメソッドを使用して、書き込む行をキューに追加する。 | |||
*: これにより、メインスレッドはブロックされることなく、次の処理に進むことができる。 | |||
* スレッドセーフ | |||
*: ミューテックスとウェイトコンディションを使用して、スレッド間の同期を行う。 | |||
<br> | |||
<u>※注意</u><br> | |||
* メモリ使用量 | |||
*: キューに大量のデータが蓄積される時、メモリ使用量が増大する可能性がある。 | |||
*: 必要に応じて、キューのサイズに制限を設けることを検討する。 | |||
* エラー処理 | |||
*: 以下の例では、エラーが発生してもすぐには検出されない。 | |||
*: リアルタイムでエラーを検出する場合は、追加機能が必要になる。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <QFile> | |||
#include <QTextStream> | |||
#include <QtConcurrent> | |||
#include <QFuture> | |||
#include <QMutex> | |||
#include <QQueue> | |||
#include <QDebug> | |||
enum class CSVError { | |||
NoError, | |||
FileOpenError, | |||
WriteError | |||
}; | |||
class CSVWriter | |||
{ | |||
private: | |||
QString m_filename; | |||
QFile m_file; | |||
QTextStream m_stream; | |||
QMutex m_mutex; | |||
QQueue<QStringList> m_queue; | |||
QWaitCondition m_condition; | |||
QFuture<void> m_future; | |||
bool m_isRunning; | |||
CSVError m_error = CSVError::NoError; | |||
private: | |||
void writeWorker() | |||
{ | |||
while (true) { | |||
QStringList row; | |||
{ | |||
QMutexLocker locker(&m_mutex); | |||
while (m_queue.isEmpty() && m_isRunning) { | |||
m_condition.wait(&m_mutex); | |||
} | |||
if (!m_isRunning && m_queue.isEmpty()) { | |||
break; | |||
} | |||
row = m_queue.dequeue(); | |||
} | |||
if (!writeRow(row)) { | |||
m_error = CSVError::WriteError; | |||
break; | |||
} | |||
} | |||
} | |||
bool writeRow(const QStringList &row) | |||
{ | |||
for (int i = 0; i < row.size(); i++) { | |||
if (!writeField(row[i])) { | |||
return false; | |||
} | |||
if (i < row.size() - 1) { | |||
m_stream << ","; | |||
} | |||
} | |||
m_stream << "\n"; | |||
return m_stream.status() == QTextStream::Ok; | |||
} | |||
bool writeField(const QString &field) | |||
{ | |||
bool needQuotes = field.contains(QRegExp("[,\"\n\r]")); | |||
if (needQuotes) { | |||
m_stream << '"' << field.replace("\"", "\"\"") << '"'; | |||
} | |||
else { | |||
m_stream << field; | |||
} | |||
return m_stream.status() == QTextStream::Ok; | |||
} | |||
public: | |||
CSVWriter(const QString &filename) : m_filename(filename), m_isRunning(false) {} | |||
~CSVWriter() | |||
{ | |||
if (m_isRunning) { | |||
waitForFinished(); | |||
} | |||
} | |||
CSVError open() | |||
{ | |||
if (!m_file.open(QIODevice::WriteOnly | QIODevice::Text)) { | |||
qDebug() << "ファイルのオープンに失敗: " << m_filename; | |||
return CSVError::FileOpenError; | |||
} | |||
m_stream.setDevice(&m_file); | |||
m_stream.setCodec("UTF-8"); | |||
m_isRunning = true; | |||
m_future = QtConcurrent::run(&CSVWriter::writeWorker, this); | |||
return CSVError::NoError; | |||
} | |||
void enqueueRow(const QStringList &row) | |||
{ | |||
QMutexLocker locker(&m_mutex); | |||
m_queue.enqueue(row); | |||
m_condition.wakeOne(); | |||
} | |||
void close() | |||
{ | |||
{ | |||
QMutexLocker locker(&m_mutex); | |||
m_isRunning = false; | |||
m_condition.wakeOne(); | |||
} | |||
waitForFinished(); | |||
m_file.close(); | |||
} | |||
void waitForFinished() | |||
{ | |||
m_future.waitForFinished(); | |||
} | |||
bool hasError() const | |||
{ | |||
return m_error != CSVError::NoError; | |||
} | |||
CSVError error() const | |||
{ | |||
return m_error; | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
int main() | |||
{ | |||
CSVWriter writer("example.csv"); | |||
CSVError error = writer.open(); | |||
if (error != CSVError::NoError) { | |||
qDebug() << "ファイルのオープンに失敗"; | |||
return -1; | |||
} | |||
QStringList headers = {"Name", "Age", "City"}; | |||
writer.enqueueRow(headers); | |||
QList<QStringList> data = { | |||
{"John Doe", "30", "New York"}, | |||
{"Jane Smith", "25", "Los Angeles"}, | |||
{"Mike Johnson", "35", "Chicago"} | |||
}; | |||
for (const auto &row : data) { | |||
writer.enqueueRow(row); | |||
} | |||
writer.close(); | |||
if (writer.hasError()) { | |||
qDebug() << "CSVファイルの書き込み中にエラーが発生"; | |||
return -1; | |||
} | |||
qDebug() << "CSVファイルの書き込みに成功"; | |||
return 0; | return 0; | ||