Delphi Programming / Object Pascal
[掲載 2021年01月26日] [更新 2021年01月26日] Delphi サンプルプログラム集 |
982_Base64 による符号化と復号化 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro
一部 Delphi XE7 以降用 |
|
982_Base64.zip [3.1 MB] 2021年01月26日版 (EXE 同梱) |
Base64 は,ASCII コードの文字や記号 64 個だけしか使用できない通信環境で,マルチバイトの文字列や画像等のバイナリ形式のデータを処理するためのエンコード方式です.Base94 は,バイナリデータを,1 バイトの ASCII コードの 64 文字だけに変換するエンコード方式です.
Delphi でテキストデータを Base64 に符号化するには,テキストデータを UTF-8 のデータにします.その UTF-8 のデータを Base64 で符号化して AnsiString 型のデータにします.
ファイルの Base64 のテキストを複合化する時は,AnsiString 型の文字列として取得します.その AnsiString 型の文字列をデコードします.デコードしたバイトデータを UTF-8 のデータにします.
|
Base64 でエンコードして保存したファイルのテキストをコピーして,例えば以下のウェブページでデコードして,元のテキストを確認することができます.
|
01_EncodeBase64 関数の引数に文字列を使用 |
Base64 のエンコードとデコードには,EncdDecd ユニット内の EncodeBase64 関数と DecodeBase64 関数が使用できます.それらの関数の引数として UTF8String 型と AnsiString 型の文字列を使用するサンプルです.
Delphi のオンラインヘルプには,EncdDecd ユニットに関するドキュメントはありません.
|
|
図1
実行時の画面 |
|
図2
保存したファイルをメモ帳で表示
- Base64 でエンコード (符号化) されている
- メモ帳は右端で折り返し表示
|
uses
EncdDecd;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
// FFilePath は String 型のグローバル変数
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
//文字列をセット
Memo1.Lines.Add(#$4F60#$597D + ' !!');
Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
Memo1.Lines.Add('テキストを Base64 で符号化して保存');
FFilePath := ExpandFileName('..\000.txt');
end;
//=============================================================================
// テキストを Base64 で符号化 ( Base64 でエンコード ) して保存
//
// 文字列を引数にしてエンコード (EncodeBase64 を使用)
// uses に EncdDecd が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LUtf8Str : UTF8String;
LAnsiStr : AnsiString;
LMemStream : TMemoryStream;
begin
// UTF-8 の文字列にする
LUtf8Str := Utf8String(Memo1.Lines.Text);
LMemStream := TMemoryStream.Create;
try
// UTF-8 のデータを Base64 に符号化
// EncodeBase64 関数の戻り値は AnsiString 型
LAnsiStr := EncodeBase64(Addr(LUtf8Str[1]), Length(LUtf8Str));
// メモリストリームに符号化した文字列を書き込んで保存
LMemStream.Clear;
LMemStream.Write(LAnsiStr[1], Length(LAnsiStr));
LMemStream.SaveToFile(FFilePath);
finally
FreeAndNil(LMemStream);
end;
end;
//=============================================================================
// Base64 で符号化して保存したテキストを読み出して複合化 ( Base64 のデコード
//
// 文字列を引数にしてデコード (DecodeBase64 を使用)
// uses に EncdDecd が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LAnsiStr : AnsiString;
LMemStream : TMemoryStream;
LByteArray : TBytes;
begin
Memo1.Lines.Clear;
LMemStream := TMemoryStream.Create;
try
// テキストファイルをメモリストリームに読み込む
LMemStream.LoadFromFile(FFilePath);
// 文字列の長さを設定
SetLength(LAnsiStr, LMemStream.Size);
// メモリストリームから文字列を読み出す
LMemStream.Position := 0;
LMemStream.Read(LAnsiStr[1], LMemStream.Size);
// Base64 の文字列をデコードしてバイト配列に格納
// DecodeBase64 関数の戻り値はバイト配列
LByteArray := DecodeBase64(LAnsiStr);
// バイト配列のデータを文字列のデータにする
// UTF-8 の指定が必要なければ StringOf メソッドが使用可能
Memo1.Lines.Text := TEncoding.UTF8.GetString(LByteArray);
finally
FreeAndNil(LMemStream);
end;
end;
Base64 にエンコードしたテキストを TStringList に格納して,以下のように,文字のエンコードの指定を ASCII にして保存すれば確実ですが,今回の場合,実際には単なるバイトデータの書き込みですから,上のコードで十分と考えられます.
|
// LStrList は TStringList 型の変数
LStrList.Add(LAnsiStr);
LStrList.SaveToFile(FFilePath, TEncoding.ASCII);
Base64 の既定では,76 文字ごとに改行文字が追加されます.1 行だけのテキストにするには,文字通り改行文字を削除します.この時,AnsiString 用の関数類を使用するようにします.
|
// 改行文字を削除
// LAnsiCRLF は AnsiString 型の変数
// uses に AnsiStrings が必要
LAnsiCRLF := #$0D#$0A;
LAnsiStr := AnsiStrings.StringReplace(LAnsiStr, LAnsiCRLF, '', [rfReplaceAll]);
Base64 のテキストを読み込んで AnsiString 型の変数のデータとする部分は,以下のようにも処理できますが,単なるハバイトデータのコピーなので,上の処理で十分と思われます.
|
LMemStream.LoadFromFile(FFilePath);
LAnsiStr := TEncoding.ASCII.GetString(LMemStream.Bytes);
02_EncodeBase64 関数の引数に TMemoryStream を使用 |
上のサンプルコードは,文字列を引数にしてエンコードとデコードしています.以下のコードは,メモリストリームを引数にして Base64 の複合化と復号化を行う例です.
|
|
図3
保存したファイルをメモ帳で表示
- Base64 の符号化と復号化の手続きの引数にメモリストリームを使用
|
リスト2
Base64 の符号化と復号化の手続きの引数にメモリストリームを使用する例 |
uses
EncdDecd;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
// FFilePath は String 型のグローバル変数
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
//文字列をセット
Memo1.Lines.Add(#$4F60#$597D + ' !!');
Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
Memo1.Lines.Add('テキストを Base64 で符号化して保存');
FFilePath := ExpandFileName('..\000.txt');
end;
//=============================================================================
// テキストを Base64 で符号化 ( Base64 でエンコード ) して保存
//
// メモリストリームを引数にしてエンコード (EncodeBase64 を使用)
// uses に EncdDecd が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LAnsiStr : AnsiString;
LMemStream : TMemoryStream;
begin
LMemStream := TMemoryStream.Create;
try
// UTF-8 の文字列にしてメモリストリームに格納
Memo1.Lines.SaveToStream(LMemStream, TEncoding.UTF8);
// UTF-8 のデータを Base64 に符号化
// EncodeBase64 関数の戻り値は AnsiString 型
LAnsiStr := EncodeBase64(LMemStream.Memory, LMemStream.Size);
// メモリストリームに符号化した文字列を書き込んで保存
LMemStream.Clear;
LMemStream.Write(LAnsiStr[1], Length(LAnsiStr));
LMemStream.SaveToFile(FFilePath);
finally
FreeAndNil(LMemStream);
end;
end;
//=============================================================================
// Base64 で符号化して保存したテキストを読み出して複合化 ( Base64 のデコード )
//
// メモリストリームを引数にしてデコード (DecodeStream を使用)
// uses に EncdDecd が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LMemStream : TMemoryStream;
LOutStream : TMemoryStream;
begin
Memo1.Lines.Clear;
LMemStream := TMemoryStream.Create;
LOutStream := TMemoryStream.Create;
try
// ファイルのデータをメモリストリームに読み込む
LMemStream.LoadFromFile(FFilePath);
// メモリストリームのデータをデコード
DecodeStream(LMemStream, LOutStream);
// デコードしたデータを UTF-8 の文字列として TMemo に表示
LOutStream.Position := 0;
Memo1.Lines.LoadFromStream(LOutStream, TEncoding.UTF8);
finally
FreeAndNil(LMemStream);
FreeAndNil(LOutStream);
end;
end;
03_TNetEncoding.Base64 を使用して Base64 の符号化と復号化 |
Delphi XE7 以降では TBase64Encoding のメソッド類が利用できます.それらのメソッド類を使用するサンプルです.
|
|
図4
保存したファイルをメモ帳で表示
- TNetEncoding.Base64 のメソッド類を使用
|
リスト3
TNetEncoding.Base64 のメソッド類を使用する Base64 の符号化と復号化 |
uses
System.NetEncoding;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
// FFilePath は String 型のグローバル変数
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
//文字列をセット
Memo1.Lines.Add(#$4F60#$597D + ' !!');
Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
Memo1.Lines.Add('テキストを Base64 で符号化して保存');
FFilePath := ExpandFileName('..\000.txt');
end;
//=============================================================================
// テキストを Base64 で符号化 ( Base64 でエンコード ) して保存
// TNetEncoding.Base64 を使用する例
// uses に System.NetEncoding が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LUtf8Str : UTF8String;
LAnsiStr : AnsiString;
LMemStream : TMemoryStream;
begin
LUtf8Str := Utf8String(Memo1.Lines.Text);
LMemStream := TMemoryStream.Create;
try
LAnsiStr := TNetEncoding.Base64.Encode(LUtf8Str);
LMemStream.Clear;
LMemStream.Write(LAnsiStr[1], Length(LAnsiStr));
LMemStream.SaveToFile(FFilePath);
finally
FreeAndNil(LMemStream);
end;
end;
//=============================================================================
// Base64 で符号化して保存したテキストを読み出して複合化 ( Base64 のデコード )
//
// TNetEncoding.Base64 を使用する例
// uses に System.NetEncoding が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LMemStream : TMemoryStream;
LOutStream : TMemoryStream;
begin
Memo1.Lines.Clear;
LMemStream := TMemoryStream.Create;
LOutStream := TMemoryStream.Create;
try
LMemStream.LoadFromFile(FFilePath);
TNetEncoding.Base64.Decode(LMemStream, LOutStream);
LOutStream.Position := 0;
Memo1.Lines.LoadFromStream(LOutStream, TEncoding.UTF8);
finally
FreeAndNil(LMemStream);
FreeAndNil(LOutStream);
end;
end;
04_Indy を使用して Base64 の符号化と復号化 |
Indy にも TIdEncoderMIME, TIdDecoderMIME
という Base64 の符号化と復号化用のコンポーネントがあります.それらのコンポーネントを使用する例です.
それらのコンポーネントは,コンポーネントパレットの [Indy Misc] タブにあります.
|
|
図5
保存したファイルをメモ帳で表示
|
リスト4
Base64 の符号化と復号化に Indy の TIdEncoderMIME, TIdDecoderMIME コンポを使用する例 |
uses
IdGlobal;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
// FFilePath は String 型のグローバル変数
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
//文字列をセット
Memo1.Lines.Add(#$4F60#$597D + ' !!');
Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
Memo1.Lines.Add('テキストを Base64 で符号化して保存');
FFilePath := ExpandFileName('..\000.txt');
end;
//=============================================================================
// テキストを Base64 で符号化 ( Base64 でエンコード ) して保存
//
// Indy (Ver 10.6.2.0) の TIdEncoderMIME コンポーネントを使用する例
// uses に IdGlobal が必要
// TIdEncoderMIME を実行時に生成して使用する場合は uses に IdCoderMIME が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LAnsiStr : AnsiString;
LMemStream : TMemoryStream;
begin
LMemStream := TMemoryStream.Create;
try
LAnsiStr := IdEncoderMIME1.Encode(Memo1.Lines.Text, IndyTextEncoding_UTF8);
LMemStream.Position := 0;
LMemStream.Write(LAnsiStr[1], Length(LAnsiStr));
LMemStream.SaveToFile(FFilePath);
finally
FreeAndNil(LMemStream);
end;
end;
//=============================================================================
// Base64 で符号化して保存したテキストを読み出して複合化 ( Base64 のデコード )
//
// Indy (Ver 10.6.2.0) の TIdDecoderMIME コンポーネントを使用する例
// uses に IdGlobal が必要
// TIdDecoderMIME を実行時に生成して使用する場合は uses に IdCoderMIME が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LMemStream : TMemoryStream;
LAnsiStr : AnsiString;
LUtf8Str : UTF8String;
begin
Memo1.Lines.Clear;
LMemStream := TMemoryStream.Create;
try
LMemStream.LoadFromFile(FFilePath);
SetLength(LAnsiStr, LMemStream.Size);
LMemStream.Position := 0;
LMemStream.Read(LAnsiStr[1], Length(LAnsiStr));
LUtf8Str := IdDecoderMIME1.DecodeString(LAnsiStr, IndyTextEncoding_UTF8);
Memo1.Lines.Text := LUtf8Str;
finally
FreeAndNil(LMemStream);
end;
end;
05_Base64 の符号化と復号化における Unicode ( UTF-16 ) |
Delphi 2009 以降の String 型は Unicode (UTF-16) です.Unicode をそのままエンコードすると,ユニコードな文字が正常にエンコードできません.Base64 の規定の処理では,Unicode のバイナリデータの一部を正常に処理できません.
図の下のコードは,その動作酔確認用のサンプルです.
結果の図を見ると,ユニコードな文字が文字化けしています.他のサンプルでデコードしても何も表示しません.本項の最初の参考リンクのテストツールでは,Shift_JIS を指定すればデコードしますが,ユニコードな文字は文字化けします.
本項の最初のサンプルで,デコード処理内のコードを以下のようにすれば Shit_JIS の指定と同じ結果になります.
汎用的な Base64 のテキストにするには,UTF-8 を使用します.
|
Memo1.Lines.LoadFromStream(LMemStream, TEncoding.UTF8);
↓
Memo1.Lines.LoadFromStream(LMemStream);
|
図6
本サンプルでエンコードしたデータを,本サンプルの Button2 クリックでデコードした結果 |
|
図7
本サンプルでエンコードしたデータを,他のサンプルでデコードした結果
- 何も表示しない
- ユニコードな文字がない場合も何も表示しない
|
|
図8
保存したファイルをメモ帳で表示
- 正常にエンコードできているように見える
- メモ帳は右端で折り返し表示
|
エンコードするテキストを ASCII 文字だけにしてみます.
ASCII 文字だけであれば正常にデコードできます.他のサンプルでも正常にデコードできます.参考リンクのテストツールでも正常にデコードできます.
ただし,Base64 既定の結果と同じにはなりません
|
|
図9
Hellow World !! というテキストをエンコードしてデコードした結果 |
|
図10
他のサンプルでエンコードした Base64 のテキスト
- ASCII (Shift_JIS) で保存されている
- これが Base64 の規定結果
|
|
図11
本サンプルでエンコードした Base64 のテキスト
- 上の図と同じ結果だが,バイナリデータは違う
- Unicode (UTF-16) で保存されている
|
下図は,Base64 にエンコードしたテキストのバイナリデータを確認した結果です.
|
|
図12
他のサンプルでエンコードした Base64 のバイナリデータ
- Base64 の規定通り 1バイト文字になっている
|
|
図13
本サンプルでエンコードした Base64 のバイナリデータ
- 2 バイト文字になっている
- Unicode (UTF-16) には 1 バイト文字はない
|
uses
EncdDecd;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
// FFilePath は String 型のグローバル変数
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
//文字列をセット
Memo1.Lines.Add(#$4F60#$597D + ' !!');
Memo1.Lines.Add(#$D842#$DFB7 + ' (サロゲートペアな文字)');
Memo1.Lines.Add('テキストを Base64 で符号化して保存');
FFilePath := ExpandFileName('..\000.txt');
end;
//=============================================================================
// Base64 エンコード
// UTF-8 を使用しない場合
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LText : string;
LStream : TMemoryStream;
begin
LText := EncodeString(Memo1.Lines.Text);
FText := LText;
LStream := TMemoryStream.Create;
try
LStream.Write(LText[1], Length(LText) * SizeOf(char));
LStream.SaveToFile(FFilePath);
finally
FreeAndNil(LStream);
end;
end;
//=============================================================================
// Base64 デコード
// UTF-8 を使用しない場合
// FText ( String 型のグローバル変数 )は上のコードでエンコードしたテキスト
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LText : string;
begin
LText := DecodeString(FText);
Memo1.Lines.Text := LText;
end;
06_テキストの Base64 による符号化と復号化 - Delphi 6 / 7 |
Delphi 6 / 7 用の Base64 符号化,複合化のサンプルコードです.Delphi 6 / 7 にも EncdDecd ユニットがありますが,EncodeBase64 という関数はありません.
Delphi 6 / 7 の String 型は AnsiString 型です.そのまま Base64 にエンコードもデコードも可能ですが,参考リンクのツールでデコードする際は,Shift_JIS を指定しなければ正常にデコードできまぜん.汎用的な処理とするには,UTF-8 を使用するのが一般的と言えます.
|
|
図14
実行時の画面 (Delphi 7) |
|
図15
保存したファイルをメモ帳で表示
|
リスト6
Delphi 6 / 7 用の Base64 符号化,複合化サンプル |
uses
EncdDecd;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
// FFilePath は String 型のグローバル変数
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('テキストを Base64 で符号化して保存');
FFilePath := ExpandFileName('..\000.txt');
end;
//=============================================================================
// テキストを Base64 で符号化 ( Base64 でエンコード ) して保存
//
// Delphi 6 / 7 用のコード
// uses に EncdDecd が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LMemStream : TMemoryStream;
LUtf8Str : UTF8String;
LAnsiStr : AnsiString;
begin
LUtf8Str := UTF8Encode(WideString(Memo1.Lines.Text));
LMemStream := TMemoryStream.Create;
try
// Base64 にエンコード
LAnsiStr := EncodeString(LUtf8Str);
LMemStream.Clear;
LMemStream.Write(LAnsiStr[1], Length(LAnsiStr));
LMemStream.SaveToFile(FFilePath);
finally
FreeAndNil(LMemStream);
end;
end;
//=============================================================================
// Base64 で符号化して保存したテキストを読み出して複合化 ( Base64 のデコード
//
// DecodeStream 手続きを使用
// Delphi 6 / 7 用のコード
// uses に EncdDecd が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LMemStream : TMemoryStream;
LDstStream : TMemoryStream;
LUtf8Str : UTF8String;
LAnsiStr : AnsiString;
begin
LMemStream := TMemoryStream.Create;
LDstStream := TMemoryStream.Create;
try
LMemStream.LoadFromFile(FFilePath);
// メモリストリーの Base64 をデコード
DecodeStream(LMemStream, LDstStream);
SetLength(LAnsiStr, LDstStream.size);
LDstStream.Position := 0;
LDstStream.Read(LAnsiStr[1], Length(LAnsiStr));
LUtf8Str := UTF8Decode(LAnsiStr);
Memo1.Lines.Text := LUtf8Str;
finally
FreeAndNil(LMemStream);
FreeAndNil(LDstStream);
end;
end;
//=============================================================================
// Base64 で符号化して保存したテキストを読み出して複合化 ( Base64 のデコード
//
// DecodeString 関数を使用
// Delphi 6 / 7 用のコード
// uses に EncdDecd が必要
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
LMemStream : TMemoryStream;
LUtf8Str : UTF8String;
LAnsiStr : AnsiString;
begin
LMemStream := TMemoryStream.Create;
try
LMemStream.LoadFromFile(FFilePath);
SetLength(LAnsiStr, LMemStream.size);
LMemStream.Position := 0;
LMemStream.Read(LAnsiStr[1], Length(LAnsiStr));
// Base64 をデコードして UTF-8 に変換
LUtf8Str := UTF8Decode(DecodeString(LAnsiStr));
Memo1.Lines.Text := LUtf8Str;
finally
FreeAndNil(LMemStream);
end;
end;
|