「Qtの基礎 - CSVファイル」の版間の差分

ナビゲーションに移動 検索に移動
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;

案内メニュー