如何使用 Indy Mime 对二进制数据进行编码?

How to encode binary data with Indy Mime?

我有一个用于存储二进制数据的 Ansi 字符串 - 字节在 0-255 范围内(我知道它应该是一个字节数组左右,但它们之间并没有太大区别)。
我想通过 Indy MIME (TIdEncoderMIME.EncodeString / TIdDecoderMIME.DecodeString) 传递这个 "binary string" 并获得人类可读的 ANSI 字符串。

我认为如果我使用 IndyTextEncoding_8Bit 编码,Encode/DecodeString 的输出将是一个只有 ANSI 字符的字符串。但是我错了!

那么,如何使用 Indy Mime 对二进制数据进行编码(类似于 application/octet-stream)?

不要对二进制数据使用 AnsiString

AnsiString 不是二进制数据的合适容器,尤其是在像 XE7 这样的 Unicode 环境中。使用 适当的 字节容器,例如 T(Id)BytesTMemoryStream

您不能通过 TId(Encoder|Decoder)MIME 字符串方法按原样传递 AnsiString ,只能 UnicodeString,因此隐式 RTL Ansi< ->Unicode 转换可能会破坏您的二进制数据。请改用面向二进制的方法 ((Encode|Decode)Bytes()(Encode|Decode)Stream())。它们的存在是有原因的。

也就是说,Indy 10 确实有一个 TIdMemoryBufferStream class(仅限桌面平台),所以如果您必须使用 AnsiString(实际上您不应该),您可以将其包装在 TStream 接口中,而无需在内存中制作额外的数据副本。例如:

var
  Binary: AnsiString;
  Strm: TIdMemoryBufferStream;
  Base64: String;
begin
  Binary := ...; // binary data
  Strm := TIdMemoryBufferStream.Create(PAnsiChar(Binary), Length(Binary));
  try
    Base64 := TIdEncoderMIME.EncodeStream(Strm);
  finally
    Strm.Free;
  end;
  // use Base64 as needed...
end;

var
  Base64: String;
  Strm: TIdMemoryBufferStream;
  Binary: AnsiString;
begin
  Base64 := ...; // encoded data
  SetLength(Binary, (Length(Base64) div 4) * 3);
  Strm := TIdMemoryBufferStream.Create(PAnsiChar(Binary), Length(Binary));
  try
    TIdDecoderMIME.DecodeStream(Base64, Strm);
    SetLength(Binary, Strm.Size);
    SetCodePage(PRawByteString(@Binary)^, 28591, False);
  finally
    Strm.Free;
  end;
  // use Binary as needed...
end;