文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…
 
(同じ利用者による、間の5版が非表示)
31行目: 31行目:
<br>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  #include <QFileDialog>
  #include <QCoreApplication>
  #include <QMessageBox>
  #include <QFile>
  #include <QTextStream>
  #include <QTextStream>
#include <iostream>
#include <vector>
#include <limits>
#include <cmath>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 数値データを生成 : sin曲線 y = sin(x)
    int iSize = 100;
    std::vector<double> lx(iSize, 0.0),
                        ly(iSize, 0.0);
    double dx = 2 * M_PI / iSize;
    for (int i = 0; i < iSize; i++) {
      lx[i] = i * dx;
      ly[i] = sin(lx[i]);
    }
    // 出力形式の選択
    int formatChoice;
    std::cout << "Choose output format:\n";
    std::cout << "1. Fixed-point notation\n";
    std::cout << "2. Scientific notation (e-notation)\n";
    std::cout << "Enter your choice (1 or 2): ";
    std::cin >> formatChoice;
    // 入力バッファをクリア
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    // 精度の設定
    int precision;
    std::cout << "Enter the number of decimal places (1-15): ";
    std::cin >> precision;
    precision = std::max(1, std::min(15, precision));  // 1から15の範囲に制限
    // 入力バッファをクリア
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    // 数値データをテキストデータに変換
    QString    strFileData;
    QTextStream strStream(&strFileData);
    strStream.setRealNumberPrecision(precision);
    if (formatChoice == 1) {
      strStream.setRealNumberNotation(QTextStream::FixedNotation);
    }
    else {
      strStream.setRealNumberNotation(QTextStream::ScientificNotation);
    }
    for(int i = 0; i < iSize; i++) {
      strStream << lx[i] << ", " << ly[i] << "\n";
    }
    // ファイル名の入力
    std::cout << "Enter the file name to save the CSV data (e.g., data.csv): ";
    std::string fileName;
    std::getline(std::cin, fileName);
    QString FileName = QString::fromStdString(fileName);
    // 全テキストデータを書き込む
    QFile File(FileName);
    if (!File.open(QIODevice::WriteOnly)) {
      std::cerr << "Unable to open file: " << File.errorString().toStdString() << std::endl;
      return -1;
    }
    QTextStream OutStream(&File);
    OutStream << strFileData;
    File.close();
    std::cout << "Data has been successfully saved to " << fileName << std::endl;
    return 0;
}
</syntaxhighlight>
<br><br>
== CSVファイル (RFC4180準拠) の読み込み ==
RFC4180は、CSVファイルの標準的な形式を定義しており、これに従うことで互換性の高いCSV処理が可能になる。<br>
<br>
以下の例では、RFC4180の規則に従ってCSVファイルを読み込んでいる。<br>
* ダブルクォートで囲まれたフィールド内のカンマと改行を正しく処理する。
* フィールド内の二重引用符 ("") を単一の引用符 ('') として解釈する。
* 各行の末尾の空白を除去する。
<br>
<syntaxhighlight lang="c++">
  #include <QFile>
  #include <QFile>
  #include <vector>
  #include <QTextStream>
  #include <math.h>
  #include <QStringList>
  #include <sstream>
  #include <QDebug>
  #include "mainwindow.h"
   
  #include "ui_mainwindow.h"
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;
          }
      }
    }
   
   
using namespace std;
    file.close();
   
   
  MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
    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)
  {
  {
     ui->setupUi(this);
     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>
<br><br>
== ストリーミング処理を使用したCSVファイルの読み込み ==
* ストリーミング処理
*: ファイル全体を1度にメモリに読み込むのではなく、1レコードずつ処理する。
*: これにより、大規模なファイルでもメモリ使用量を抑えることができる。
* コールバック関数
*: 各レコードの処理をコールバック関数として渡すことにより、柔軟な処理が可能になる。
<br>
<syntaxhighlight lang="c++">
#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <functional>
#include <QDebug>
enum class CSVError {
    NoError,
    FileOpenError,
    ReadError,
    ParseError
};
class CSVReader
{
private:
    QString m_filename;
public:
    CSVReader(const QString &filename) : m_filename(filename) {}
    CSVError readCSV(std::function<void(const QStringList&)> 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 line;
      QStringList fields;
      bool inQuotes = false;
      QString field;
      qint64 lineNumber = 0;
      while (!in.atEnd()) {
          QChar ch;
          in >> ch;
          if (in.status() != QTextStream::Ok) {
            qDebug() << "読み込みエラー:" << m_filename << "行:" << lineNumber;
            return CSVError::ReadError;
          }
          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()) {
                  rowCallback(fields);
                  fields.clear();
                  lineNumber++;
                }
            }
            else {
                field += ch;
            }
          }
      }
      if (inQuotes) {
          qDebug() << "パースエラー: 閉じていない引用符があります。行:" << lineNumber;
          return CSVError::ParseError;
      }
      file.close();
   
   
MainWindow::~MainWindow()
      return CSVError::NoError;
    }
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
int main()
  {
  {
     delete ui;
     CSVReader reader("example.csv");
    CSVError error = reader.readCSV([](const QStringList& row) {
      // 各レコードの処理
      qDebug() << row;
    });
    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;
  }
  }
</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>
   
   
  void MainWindow::OnButtonClicked()
  enum class CSVError {
    NoError,
    FileOpenError,
    WriteError
};
 
class CSVWriter
  {
  {
     // Input File Name
private:
     QString FileName = QFileDialog::getSaveFileName(this, tr("Save CSV File"), "", tr("CSV (*.csv);;All Files (*)"));
    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;
    }
   
   
     if(FileName.isEmpty())
public:
     { // Cancel
     CSVWriter(const QString &filename) : m_filename(filename), m_isRunning(false) {}
       return;
    ~CSVWriter()
     {
       if (m_isRunning) {
          waitForFinished();
      }
     }
     }
   
   
     // Generate CSV Data
     CSVError open()
     int iSize = 100;
     {
     vector<double> lx(iSize, 0.0f),
      if (!m_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
                  ly(iSize, 0.0f);
          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();
    }
   
   
     double dx = 2 * 3.15159 / iSize;
     bool hasError() const
    for(int i = 0; i < iSize; i++)
     {
     {
       lx[i] = i * dx;
       return m_error != CSVError::NoError;
      ly[i] = sin(vx);
     }
     }
   
   
     // Convert from Double to String
     CSVError error() const
    QString strFileData = "";
    //stringstream ss;
    for(int i = 0; i < iSize; i++)
     {
     {
        strFileData += lx[i] + ", " + ly[i] + "\n";
      return m_error;
        //ss << lx[i] << "," << ly[i] << endl;
     }
     }
      
};
     // Write to File
</syntaxhighlight>
     QFile File(FileName);
<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;
}
</syntaxhighlight>
<br><br>


    if(!File.open(QIODevice::WriteOnly))
== 分割処理を使用したCSVファイルの読み込み ==
    {
以下の例では、RFC4180に準拠したCSVファイルを分割読み込みしている。<br>
        QMessageBox::information(this, tr("Unable to open file"), File.errorString());
分割処理は、大規模な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;
   
   
        return;
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;
     }
     }
   
   
     QTextStream OutStream(&File);
public:
    // 浮動小数点をe形式にする
    CSVReader(const QString &filename, qint64 chunkSize = 1024 * 1024) : m_filename(filename), m_chunkSize(chunkSize) {}
    //OutStream.setRealNumberNotation(QTextStream::ScientificNotation);
    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行まで読み込みして中断
    //OutStream.setRealNumberNotation(QTextStream::FixedNotation);
      if (lineNumber >= 99) {
          qDebug() << "100行読み込んだので中断します";
          return false;
      }
   
   
    // 浮動小数点の桁数を設定
      return true; // 続けて読み込む
     OutStream.setRealNumberPrecision(3);
     });
   
   
     OutStream << strFileData;
     switch (error) {
    //OutStream << ss.str().c_str();
      case CSVError::NoError:
          qDebug() << "CSVファイルの読み込みに成功";
          break;
      case CSVError::FileOpenError:
          qDebug() << "ファイルのオープンに失敗";
          break;
      case CSVError::ReadError:
          qDebug() << "ファイルの読み込み中にエラーが発生";
          break;
      case CSVError::ParseError:
          qDebug() << "CSVのパース中にエラーが発生";
          break;
    }
   
   
     File.close();
     return 0;
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>


{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Qt]]
[[カテゴリ:Qt]]