QByteArray簡単入門


QtはQByteArrayによってバイト配列コンテナを提供してくれた.QByteArrayは、元のバイトを格納するために使用することもできるし、'0'を含むこともできるし、従来の8ビットの'0'で終わる文字列を格納するために使用することもできる.QByteArrayを使うのは普通のconst char*を使うより便利です.さらに、最下位レベルでは、格納されたデータが'0'で終わることを保証し、暗黙的な共有(書き込み時コピー)ポリシーによってメモリの使用と不要なデータコピーを削減することができます.
もちろん、QByteArrayに加えて、QtはQStringクラスの文字列を格納することも提供します.また、ほとんどの場合、QStringを使用することを選択します.QStringは16ビットのUnicode文字を格納しているので、アプリケーションでQStringを使用するとnon-ASCII/non-Latin-1文字を格納しやすくなります.また,QStringはQtライブラリ全体においても多く用いられている.QtライブラリがQByteArrayを提供する用途には、主に2つの側面があります.1つは、元のバイナリデータを格納するために使用され、2つは、メモリが緊張している場合、例えば埋め込みデバイス上に使用されます.
QByteArrayを具体的に使用する一般的な方法は、const char*を直接その構造関数に伝えることです.たとえば、次のコードは、サイズ5の文字配列を構築します.このコードには、「hello」というデータが含まれています.
QByteArray ba("Hello");

このオブジェクトに対してsize()メンバー関数を呼び出すと5が返されますが、QByteArrayには文字列の最後に'0'が含まれています.これにより、関数がオブジェクトの最下位データを指すポインタを必要とする場合、ポインタが指すデータが'0'で終わることを保証します.また、このようにQByteArrayオブジェクトを作成する場合、QByteArrayは深いコピーを行うため、QByteArrayのオブジェクトを作成した後、プログラムに副作用を及ぼさずにパラメータとしての文字列を変更することもできます.もちろん、パフォーマンスを考慮して深くコピーしたくない場合は、QByteArrayの静的メソッドfromRawData()を使用してQByteArrayオブジェクトを作成できます.
QByteArrayオブジェクトを作成するもう1つの方法は、resize()関数を使用してオブジェクトのサイズ、すなわち格納するバイト数を設定し、1バイト1バイトの初期化です.QByteArrayはc++配列と同様に0ベースのインデックスを使用し、[]演算子を提供するため、この方法も非常に便利です.例:
  QByteArray ba;
  ba.resize(5);
  ba[0] = 0x3c;
  ba[1] = 0xb8;
  ba[2] = 0x64;
  ba[3] = 0x18;
  ba[4] = 0xca;

アクセスする各バイトについては、上の[]演算子のほかに、at()メンバー関数も使用できます.さらに,at()は通常,[]演算子よりも高速であり,深いコピーが発生しないためである.たとえば、次のコードがあります.
  for (int i = 0; i < ba.size(); ++i) {
      if (ba.at(i) >= 'a' && ba.at(i) <= 'f')
          cout << "Found character in range [a-f]" << endl;
  }

複数バイトを一度に抽出したい場合はleft()、right()、mid()メンバー関数を使用します.
QByteArrayは、元のバイナリデータを格納するために一般的に使用されています.したがって、QByteArrayに'0'を格納することができる.メンバー関数size()は、中間の'0'を含む配列全体のサイズを返すことができますが、QByteArrayによって最後の'0'に自動的に追加されることは含まれません.例:
  QByteArray ba1("ca\0r\0t");
  ba1.size();                     // Returns 2.
  ba1.constData();                // Returns "ca" with terminating \0.

  QByteArray ba2("ca\0r\0t", 3);
  ba2.size();                     // Returns 3.
  ba2.constData();                // Returns "ca\0" with terminating \0.

  QByteArray ba3("ca\0r\0t", 4);
  ba3.size();                     // Returns 4.
  ba3.constData();                // Returns "ca\0r" with terminating \0.

  const char cart[] = {'c', 'a', '\0', 'r', '\0', 't'};
  QByteArray ba4(QByteArray::fromRawData(cart, 6));
  ba4.size();                     // Returns 6.
  ba4.constData();                // Returns "ca\0r\0t" without terminating \0.

さらに,qstrlen()関数を用いて,最初の'0'より前の文字列の長さを得ることができる.また、QByteArrayオブジェクトの作成についてはresize()関数について説明していますが、この関数を呼び出すと、新しく割り当てられたバイトは定義されず、これらのバイトに特定の値を設定するためにfill()関数を使用することができます.
operator[]とat()関数を使用してアクセスするほか、data()とconstData()を使用して配列の最下位のデータのポインタを直接得ることもできます.この返されるポインタは、次回non-const関数が呼び出されるまで有効になります.また、QByteArrayオブジェクトがraw dataによって作成されていない限り、これらのデータは'0'で終わることも確認できます.返される文字列には、QByteArrayが最後の'0'に追加されることも自動的に保護されます.
QByteArrayの変更では、append()、prepend()、insert()、replace()、remove()など、多くの基礎関数が提供されます.たとえば、次のようになります.
  QByteArray x("and");
  x.prepend("rock ");         // x == "rock and"
  x.append(" roll");          // x == "rock and roll"
  x.replace(5, 3, "&");       // x == "rock & roll"

ここで、replace()とremove()関数の最初の2つのパラメータは、削除を開始する位置と削除する文字の個数を指します.
空でない配列にデータを追加すると、配列は空間を再割り当てしてデータをコピーします.パフォーマンスの問題を考慮すると、reserve()関数を事前に呼び出して、配列に一部の空間を事前に割り当てることもできます.これにより、追加データのたびに再割り当てされるオーバーヘッドを省くことができます.QByteArrayが現在実際に割り当てられているメモリの数を取得するには、capacity()関数を使用します.
空の配列にデータを追加してもコピーは発生しません.
私たちが実際に開発して使用する場合、バイト配列の両端から空白文字を削除する必要があることがよくあります.例えば、','t','などです.この場合、trimmed()関数を使用することができます.両端の空白文字を削除しながら、中間に連続する複数の空白文字を1つに置き換えたい場合はsimplified()関数を使用します.
同様に、QByteArrayの検索もindexOf()およびlastIndexOf()を提供する.名前の通り、一つは前から後へ、一つは後ろから前へ.検索に成功すると、文字またはサブ列の下付き位置が返されます.そうしないと、-1が返されます.文字やサブストリングが含まれているかどうかを検出するだけであれば、contains()関数を簡単に使用できます.特定の文字やサブストリングがバイト配列に何回現れたかを知りたい場合はcount()関数を使用します.文字またはサブストリングの置換も同様で、replace()関数を使用できます.
最後に、QByteArrayは、履歴上、nullとバイト配列が空であることを区別する.nullは、QByteArrayのデフォルトのコンストラクション関数を使用して作成されたバイト配列を示します.空のバイト配列は、サイズ0のバイト配列です.それらの関係は,nullバイト配列は必ず空の配列であるが,逆に成り立たない.覚えておいて!
  QByteArray().isNull();          // returns true
  QByteArray().isEmpty();         // returns true

  QByteArray("").isNull();        // returns false
  QByteArray("").isEmpty();       // returns true

  QByteArray("abc").isNull();     // returns false
  QByteArray("abc").isEmpty();    // returns false

ただし,QByteArrayのクラスメンバ関数ではisNull()を除いた他のメンバ関数は,これら2つの配列を同等に扱う.たとえば、data()関数はnullバイト配列に対しても空のポインタではなく'0'文字を指すポインタを返します.また、QByteArray()は、QByteArray(")と同等である.したがって、isNull()ではなくisEmpty()を使用することをお勧めします.
QByteArrayに関する多くの情報と使い方について説明しましたが、次に、QByteArrayに関連する他の2つのクラスを簡単に説明します.1つはQByteArrayListで、1つはQByteArrayMatcherです.
QByteArrayListは、その名の通りQByteArrayのチェーンテーブルであり、QListに類似している.したがって、すべてのQListの関数をQByteArrayListに適用することができる.たとえば、isEmpty()を使用してチェーンテーブルが空であるかどうかをテストし、append()、prepend()、insert()、replace()、待機関数を使用してQByteArrayListを変更できます.これらのQListの関数に加えて、QByteArrayListにはいくつかのjoin()関数が追加され、QByteArrayListの要素を個別のQByteArrayに接続することができる.
また、QtライブラリがQByteArrayListを提供する目的は、QStringListとは全く異なる.たとえば、QStringListには要素を操作するメンバー関数がたくさんありますが、QByteArrayListにはありません.通常、印刷可能クラス文字列のリストを表示したい場合は、QStringListが優先されます.QByteArrayListは、通常、1つの順序のioデバイスからデータを受信する場合など、効率的に多数のバイナリデータを接続するために使用される.
QByteArrayMatcherクラスは、QByteArrayで効率的にバイトシーケンスを繰り返し検索するために使用されます.検索を繰り返す場合、QByteArrayのindexOf()を直接使用するよりも、クラスのオブジェクトとそのメンバー関数indexIn()を使用する方が効率的です.しかし、このクラスは、単一バイトの検索に対してより効率的ではありません.検索するQByteArrayシーケンスを使用してQByteArrayMatcherのオブジェクトを作成し、indexIn()メンバー関数を使用してターゲットバイト配列を検索します.indeIn()の具体的な声明は以下の通りです.
int QByteArrayMatcher::indexIn(const QByteArray &ba, int from = 0) const
int QByteArrayMatcher::indexIn(const char *str, int len, int from = 0) const

検索に成功した場合、サブバイト配列のターゲット配列の下付き位置を返します.検索に失敗した場合は、-1を返します.
QByteArrayMatcherのオブジェクトを作成するときに、検索するpatternが転送されない場合は、後でsetPattern()で設定することもできます.
QByteArray QByteArrayMatcher::pattern() const
void QByteArrayMatcher::setPattern(const QByteArray &pattern)

このような場合、コンソールプログラムを作成して、簡単なプレゼンテーションを行います.
プロジェクトを新規作成する手順は省略して、Qt Creatorを起動し、ファイル->新規ファイルまたはプロジェクト->Qt Console Applicationをクリックします.
次に、テストコードを示します.
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QByteArray array("Hello ");
    array.append("world ");
    array.prepend("you ");
    qDebug() << "Origin byte array: " << array;

    QByteArrayMatcher matcher("world");
    int pos = matcher.indexIn(array);
    if(pos == -1)
    {
        qDebug() << "Search failed";
    }
    else
    {
        qDebug() << "The position is " << pos;
    }

    QByteArrayList byteList;
    byteList << "I" << "like" << "Qt";
    qDebug() << "byteList: " << byteList;
    QByteArray joinArray = byteList.join("-");
    qDebug() << "joinArray: " << joinArray;

    return a.exec();
}