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 による符号化と復号化


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 でエンコード (符号化) されている
  • メモ帳は右端で折り返し表示

リスト1
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
保存したファイルをメモ帳で表示
  • Indy のコンポーネントを使用

リスト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 バイト文字はない

リスト5
UTF-8 を使用しないコード
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;