Delphi Programming / Object Pascal

[掲載 2018年06月09日] [更新 2018年07月08日] Delphi 一般・その他 |
| Move 関数によるバイトデータと文字または文字列の操作 |
| 動作確認等 |
Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 |
| 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 型の文字配列に変換 |
//=============================================================================
// バイト型配列のデータを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 メソッドを使用してバイト配列のデータを作成する例
|
//=============================================================================
// バイト型配列のデータを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 型の文字列の変換 |
//=============================================================================
// バイト型配列のデータを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 型の文字列に変換 |
//=============================================================================
// バイト型配列のデータを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 型の文字列をバイト配列のデータに変換 |
//=============================================================================
// 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;
バイト配列のデータと数値との相互変換のサンプルです。
まず数値を Move 関数を使用して、バイト配列のデータにします。そのバイト配列のデータを Move 関数を使用して別の数値の変数のデータとしてコピーします。
整数型と実数型の数値でテストしています。 |
 |
図6
バイト配列データと数値との変換
|
 |
図7
バイト配列データと数値との変換
|
//=============================================================================
// バイト型配列のデータと数値の変換
//
// テスト用の数値をバイト配列データとして格納
// そのバイト配列のデータを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' はコピー先のバイトデータ
- 最後の行がコピーした結果のデータ
|
//=============================================================================
// バイト型配列のデータを別のバイト配列にコピー
//
// コピー元のバイト配列の任意の要素から指定バイト数をコピー
// コピー先のバイト配列の任意の位置へコピー(上書き)
//
// 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;
|