Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2018年06月09日] [更新 2018年07月08日] Delphi 一般・その他
Move 関数によるバイトデータと文字または文字列の操作
動作確認等 Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
[整理番号 - 0790]







Move 関数によるバイトデータと文字または文字列の操作


Move 関数を使用した バイト配列と,Char 型の文字配列や文字列との変換関係のサンプルです. バイトデータを文字列に変換したり,文字列をバイトデータに変換するには TEncoding の機能を利用すれば簡単ですが,Move 関数も便利なことがあります.

サンプルで使用している関数名は Move ですが,実際にはバイト単位でのデータのコピーです.
これらの変換が必要な場面は,アプリケーションの処理の場面や状況によって異なります.したがって,Move 関数による変換が必ずしも適切というわけではありません.Move 関数の代わりに Windows API の CopyMemory 関数あるいは MoveMemory 関数も利用できます.



[備考 1]
サンプルの中には,Move 関数の代わりに StrPCopy, StrCopy, StrPLCopy や StrLCopy 等の関数を使用しても変換あるいはコピーが可能なサンプルがあります.これらの Null 終端文字列のコピールーチンは,内部で Move 関数を使用して処理を行っています.


[備考 2]
TBytesStream, TStringStream にもバイト操作用のメソッドやプロパティが実装されています.





01_バイト配列のデータと Char 型の文字配列データとの変換


バイト配列のデータを Char 型の文字配列のデータに変換するサンプルです.Char 型の文字配列のデータをバイト配列のデータにコピーする具体的なコードは掲載していませんが,Move 関数の引数を逆にすれば変換できます.

文字列をバイト配列に格納した後,Move 関数を使用してバイト配列のデータを Char 型の文字配列にコピーします.バイト配列が動的配列の場合と静的配列の場合,また,Char 型の動的配列と Char 型の静的配列の両方でテストしています,
Char 型の文字配列のデータを文字列として取り出すには,Null 終端の文字が必要です.



図1
バイト配列のデータを Char 型の文字配列に変換

リスト1
//=============================================================================
//  バイト型配列のデータをChar型の文字配列のデータにする例
//
//  テスト用の文字列をバイト型の配列データに格納
//  そのバイト配列データをChar型の文字配列にコピーする
//
//  TBytesはバイト型の動的配列
//  TCharArrayはChar型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText       : string;
  LByteArr    : TBytes;
  LCharArrDst : TCharArray;
  LByteSize   : Integer;
  LTextDst    : string;
begin
  Memo1.Lines.Clear;

  //テスト用の文字列
  LText := 'バイト配列データを Char 型の文字配列に' + sLineBreak
         + 'バイト配列 : 動的配列' + sLineBreak
         + 'Char 型配列 : 動的配列';

  //バイト配列のサイズを設定して
  //String型の文字列をバイト配列にコピー
  LByteSize := Length(LText) * SizeOf(Char);
  SetLength(LByteArr, LByteSize);
  Move(LText[1], LByteArr[0], LByteSize);
  //テスト用バイト配列データ作成終了


  //バイト配列のデータをChar型の配列にコピー
  //Null終端文字分を含めたサイズが必要
  LByteSize := Length(LByteArr);
  SetLength(LCharArrDst, LByteSize div SizeOf(Char) + SizeOf(Char));
  Move(LByteArr[0], LCharArrDst[0], LByteSize);

  //結果の表示
  LTextDst := PChar(@LCharArrDst[0]);
  Memo1.Lines.Add(LTextDst);
end;

//=============================================================================
//  バイト型配列のデータをChar型の文字配列のデータにする例
//
//  テスト用の文字列をバイト型の配列データに格納
//  そのバイト配列データをChar型の文字配列にコピーする
//
//  TByteArrayはバイト型の静的配列
//  TCharArrayはChar型の動的配列
//
//  元のバイト配列が静的配列で初期化しているのでにNull終端文字分は不要
//  ただし配列のサイズがNull終端分を含むサイズであること
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LText       : string;
  LByteArr    : TByteArray;
  LCharArrDst : TCharArray;
  LByteSize   : Integer;
  LTextDst    : string;
begin
  Memo1.Lines.Clear;

  //テスト用の文字列
  LText := 'バイト配列データを Char 型の文字配列に' + sLineBreak
         + 'バイト配列 : 静的配列' + sLineBreak
         + 'Char 型配列 : 動的配列';

  //バイト配列を初期化して
  //String型の文字列をバイト配列にコピー
  LByteSize := Length(LText) * SizeOf(Char);
  FillChar(LByteArr, SizeOf(LByteArr), 0);
  Move(LText[1], LByteArr[0], LByteSize);
  //テスト用バイト配列データ作成終了


  //バイト配列のデータをChar型の配列にコピー
  LByteSize := Length(LByteArr);
  SetLength(LCharArrDst, LByteSize div SizeOf(Char));
  Move(LByteArr[0], LCharArrDst[0], LByteSize);

  //結果の表示
  LTextDst := PChar(@LCharArrDst[0]);
  Memo1.Lines.Add(LTextDst);
end;

//=============================================================================
//  バイト型配列のデータをChar型の文字配列のデータにする例
//
//  テスト用の文字列をバイト型の配列データに格納
//  そのバイト配列データをChar型の文字配列にコピーする
//
//  TByteArrayはバイト型の静的配列
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LText       : string;
  LByteArr    : TByteArray;
  LCharArrDst : array [0..199] of Char;
  LByteSize   : Integer;
  LTextDst    : string;
begin
  Memo1.Lines.Clear;

  //テスト用の文字列
  LText := 'バイト配列データを Char 型の文字配列に' + sLineBreak
         + 'バイト配列 : 静的配列' + sLineBreak
         + 'Char 型配列 : 静的配列';

  //バイト配列を初期化して
  //String型の文字列をバイト配列にコピー
  LByteSize := Length(LText) * SizeOf(Char);
  FillChar(LByteArr, SizeOf(LByteArr), 0);
  Move(LText[1], LByteArr[0], LByteSize);
  //テスト用バイト配列データ作成終了


  //バイト配列のデータをChar型の配列にコピー
  LByteSize := Length(LByteArr);
  FillChar(LCharArrDst, Length(LCharArrDst) * SizeOf(Char), #0);
  Move(LByteArr[0], LCharArrDst[0], LByteSize);

  //結果の表示
  LTextDst := LCharArrDst;
  Memo1.Lines.Add(LTextDst);
end;


String 型の文字列からバイト配列を作成する際,TEncoding クラスの GetBytes メソッドが使用できます.その例です.エンコードは Unicode を指定します.



図2
バイト配列のデータを Char 型の文字配列に変換
  • TEncoding クラスの GetBytes メソッドを使用してバイト配列のデータを作成する例

リスト2
//=============================================================================
//  バイト型配列のデータをChar型の文字配列のデータにする例
//
//  テスト用の文字列をバイト型の配列データとして格納
//  そのバイト配列データをChar型の文字配列にコピーする
//
//  変換元のバイト配列データをTEncodingの機能を使用して作成する例
//
//  TCharArrayはChar型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText       : string;
  LCharArrDst : TCharArray;
  LByteArr    : TBytes;
  LByteSize   : Integer;
  LTextDst    : string;
begin
  Memo1.Lines.Clear;

  LText := 'バイト配列データを Char 型の文字配列に' + sLineBreak
         + 'バイト配列データ作成に TEncoding を利用';
  LByteArr := TEncoding.Unicode.GetBytes(LText.ToCharArray);

  //バイト配列のデータをChar型の配列にコピー
  LByteSize := Length(LByteArr);
  SetLength(LCharArrDst, LByteSize);
  Move(LByteArr[0], LCharArrDst[0], LByteSize);

  //結果の表示
  LTextDst := PChar(@LCharArrDst[0]);
  Memo1.Lines.Add(LTextDst);
end;




02_バイト配列のデータと String 型の文字列との変換


バイト配列のデータと String 型の文字列との相互変換のサンプルです.



図3
バイト配列のデータと String 型の文字列の変換

リスト3
//=============================================================================
//  バイト型配列のデータをString型の文字列にする
//
//  テスト用の文字列をバイト型の配列データとして格納
//  そのバイト配列データをString型の文字列にコピーする
//
//  TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText      : string;
  LStringDst : string;
  LByteArr   : TBytes;
  LByteSize  : Integer;
begin
  Memo1.Lines.Clear;

  //テスト用の文字列
  LText := 'バイト配列データを String 型の文字列に' + sLineBreak
         + 'バイト配列 : 動的配列';

  //バイト配列のサイズを設定して
  //String型の文字列をバイト配列にコピー
  LByteSize := Length(LText) * SizeOf(Char);
  SetLength(LByteArr, LByteSize);
  Move(LText[1], LByteArr[0], LByteSize);
  //テスト用バイト配列データ作成終了


  //バイト配列のデータをString型の文字列のデータにする
  //String型の文字列の最初の文字の要素番号は1であることに注意
  LByteSize := Length(LByteArr);
  SetLength(LStringDst, LByteSize div SizeOf(Char));
  Move(LByteArr[0], LStringDst[1], LByteSize);

  //結果の表示
  Memo1.Lines.Add(LStringDst);
end;

//=============================================================================
//  バイト型配列のデータをString型の文字列にする
//
//  テスト用の文字列をバイト型の配列データとして格納
//  そのバイト配列データをString型の文字列にコピーする
//
//  TByteArrayはバイト型の静的配列
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LText      : string;
  LStringDst : string;
  LByteArr   : TByteArray;
  LByteSize  : Integer;
begin
  Memo1.Lines.Clear;

  //テスト用の文字列
  LText := 'バイト配列データを String 型の文字列に' + sLineBreak
         + 'バイト配列 : 静的配列';

  //バイト配列のサイズを設定して
  //String型の文字列をバイト配列にコピー
  LByteSize := Length(LText) * SizeOf(Char);
  Move(LText[1], LByteArr[0], LByteSize);
  //テスト用バイト配列データ作成終了


  //バイト配列のデータをString型の文字列のデータにする
  //String型の文字列の最初の文字の要素番号は1であることに注意
  LByteSize := Length(LByteArr);
  SetLength(LStringDst, LByteSize div SizeOf(Char));
  Move(LByteArr[0], LStringDst[1], LByteSize);

  //結果の表示
  Memo1.Lines.Add(LStringDst);
end;




03_バイト配列のデータと PChar 型の文字列との変換


Move 関数を使用してバイト配列のデータを PChar 型の文字列に変換するサンプルです.



図4
バイト配列のデータを PChar 型の文字列に変換

リスト4
//=============================================================================
//  バイト型配列のデータをPChar型の文字列にする
//
//  テスト用の文字列をバイト型の配列データに格納
//  そのバイト配列データをPChar型の文字列にコピーする
//
//  TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LText     : string;
  LPCharDst : PChar;
  LByteArr  : TBytes;
  LByteSize : Integer;
begin
  Memo1.Lines.Clear;
  //テスト用の文字列
  LText := 'バイト配列データを PChar 型の文字列に';

  //バイト配列のサイズを設定して
  //String型の文字列をバイト配列にコピー
  LByteSize := Length(LText) * SizeOf(Char);
  SetLength(LByteArr, LByteSize);
  Move(LText[1], LByteArr[0], LByteSize);
  //テスト用バイト配列データ作成終了


  //バイト配列のデータをPChar型の文字列のデータにする
  //Null文字分のメモリも確保しておく
  //AllocMem関数はメモリを0に初期化するので文字でない末尾はNull文字となる
  LPCharDst := AllocMem(LByteSize + SizeOf(Char));
  try
    Move(LByteArr[0], LPCharDst^, LByteSize);

    //結果の表示
    Memo1.Lines.Add(LPCharDst);
  finally
    FreeMem(LPCharDst);
  end;
end;


上のサンプルとは逆に,Move 関数を使用して PChar 型の文字列のデータをバイト配列のデータとしてコピーするサンプルです.



図5
PChar 型の文字列をバイト配列のデータに変換

リスト5
//=============================================================================
//  PChar型の文字列のデータをバイト配列にコピーする
//
//  TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LPCharSrc : PChar;
  LByteArr  : TBytes;
  LByteSize : Integer;
begin
  Memo1.Lines.Clear;

  //テスト用文字列
  LPCharSrc := 'PChar 型の文字列をバイト配列データに';

  //バイト配列のサイズを設定して
  //PChar型の文字列データをバイト配列にコピー
  //結果を文字列として取得するにはNull終端文字の分の確保が必要
  //PChar型の文字列のNull終端文字もコピーする
  LByteSize := (StrLen(LPCharSrc) + 1) * SizeOf(Char);
  SetLength(LByteArr, LByteSize);
  Move(LPCharSrc^, LByteArr[0], LByteSize);

  //結果の表示
  Memo1.Lines.Add(PChar(LByteArr));
end;




04_バイト配列のデータと 数値との変換


バイト配列のデータと数値との相互変換のサンプルです.
まず数値を Move 関数を使用して,バイト配列のデータにします.そのバイト配列のデータを Move 関数を使用して別の数値の変数のデータとしてコピーします.
整数型と実数型の数値でテストしています.



図6
バイト配列データと数値との変換
  • 整数型の数値の例
図7
バイト配列データと数値との変換
  • 実数型の数値の例

リスト6
//=============================================================================
//  バイト型配列のデータと数値の変換
//
//  テスト用の数値をバイト配列データとして格納
//  そのバイト配列のデータをInteger型の数値として取り出す
//
//  TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LIntegerSrc : Integer;
  LIntegerDst : Integer;
  LByteArr    : TBytes;
  LByteSize   : Integer;
begin
  Memo1.Lines.Clear;

  //テスト用の数値
  LIntegerSrc := 123456;

  //バイト配列のサイズを設定して数値をバイト配列に格納
  LByteSize := SizeOf(Integer);
  SetLength(LByteArr, LByteSize);
  Move(LIntegerSrc, LByteArr[0], LByteSize);

  //バイト配列のデータを数値の変数にコピー
  Move(LByteArr[0], LIntegerDst, SizeOf(Integer));

  //結果の表示
  Memo1.Lines.Add('バイト配列データと整数値の変換');
  Memo1.Lines.Add(IntToStr(LIntegerDst));
end;

//=============================================================================
//  バイト型配列のデータと数値の変換
//
//  テスト用の数値をバイト配列データとして格納
//  そのバイト配列のデータをIDouble型の数値として取り出す
//
//  TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LDoubleSrc : Double;
  LDoubleDst : Double;
  LByteArr   : TBytes;
  LByteSize  : Integer;
begin
  Memo1.Lines.Clear;

  //テスト用の数値
  LDoubleSrc := 1.23456E+12;

  //バイト配列のサイズを設定して数値をバイト配列に格納
  LByteSize := SizeOf(Double);
  SetLength(LByteArr, LByteSize);
  Move(LDoubleSrc, LByteArr[0], LByteSize);

  //バイト配列のデータを数値の変数にコピー
  Move(LByteArr[0], LDoubleDst, SizeOf(Double));

  //結果の表示
  Memo1.Lines.Add('バイト配列データと実数値の変換');
  Memo1.Lines.Add(FormatFloat('0.000E+00', LDoubleDst));
end;




05_読み出しと書き込み位置を指定したバイト配列のコピー


バイト配列は要素番号 (インデックスの番号) で先頭からのバイト位置を指定できます.Move 関数ではコピーするバイト数が設定できます.このことを利用すると,コピー元のバイト配列の任意の位置から指定バイト数だけをコピー先のバイト配列にコピーできます.その例です.

テスト用のバイトデータとして 1 バイトの文字である AnsiString の ASCII 文字を使用しています.
TMemo にデータを表示する際,string で型キャストしています.これは「W1057 文字列の暗黙のキャスト ('AnsiString' から 'string')」という警告を回避するためです.



図8
バイト配列データを別のバイト配列にコピー
  • 'ABCDEFG' はコピー元のバイトデータ
  • '123456789' はコピー先のバイトデータ
  • 最後の行がコピーした結果のデータ

リスト7
//=============================================================================
//  バイト型配列のデータを別のバイト配列にコピー
//
//  コピー元のバイト配列の任意の要素から指定バイト数をコピー
//  コピー先のバイト配列の任意の位置へコピー(上書き)
//
//  TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LByteArrSrc : TBytes;
  LByteArrDst : TBytes;
  LText       : AnsiString;
begin
  Memo1.Lines.Clear;

  Memo1.Lines.Add('バイト配列のデータを別のバイト配列にコピー');
  Memo1.Lines.Add('');

  //データをバイト配列に格納して確認表示
  LText :='ABCDEFG';
  SetLength(LByteArrSrc, Length(LText));
  Move(LText[1], LByteArrSrc[0], Length(LText));
  Memo1.Lines.Add(string(LText));

  //別のデータを別のバイト配列に格納して確認表示
  LText :='123456789';
  SetLength(LByteArrDst, Length(LText));
  Move(LText[1], LByteArrDst[0], Length(LText));
  Memo1.Lines.Add(string(LText));


  //バイト配列のデータを別のバイト配列にコピー
  Move(LByteArrSrc[2], LByteArrDst[3], 4);


  //コピー先のバイト配列のデータを文字列に変換
  SetLength(LText, Length(LByteArrDst));
  Move(LByteArrDst[0], LText[1], Length(LByteArrDst));

  //その文字列を結果として表示
  Memo1.Lines.Add('');
  Memo1.Lines.Add(string(LText));
end;