如何使用Indy Mime编码二进制数据?
问题描述:
我有一个Ansi字符串,我用它来存储二进制数据 - 在0-255范围内的字节(我知道它应该是一个字节数组左右,但它们之间差别不大)。
我想通过Indy MIME(TIdEncoderMIME.EncodeString/TIdDecoderMIME.DecodeString)传递这个“二进制字符串”,并获得一个人类可读的字符串。如何使用Indy Mime编码二进制数据?
我认为如果我使用IndyTextEncoding_8Bit编码,Encode/DecodeString的输出将是只有ANSI字符的字符串。但是我错了!
那么,如何用Indy Mime编码二进制数据(类似于application/octet-stream)?
答
对二进制数据不要使用AnsiString
!
AnsiString
不适合二进制数据的容器,特别是在像XE7这样的Unicode环境中。代替使用正确的字节容器,如T(Id)Bytes
或TMemoryStream
。
你不可错过AnsiString
原样通过TId(Encoder|Decoder)MIME
字符串方法,只有UnicodeString
,所以隐含的RTL安思< - > Unicode转换可能会损坏您的二进制数据。改为使用面向二进制的方法((Encode|Decode)Bytes()
,(Encode|Decode)Stream()
)。他们的存在是有原因的。
话虽这么说,印第10确实有TIdMemoryBufferStream
类(仅限桌面平台),所以如果你必须使用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;
感谢。我将我的代码转换为使用TIDBytes。有用。但有一个问题:为什么不应该使用AnsiString来存储二进制数据? AnsiString只不过是一个字节数组而已。只要你不把它转换成字符串,一切都应该没问题。 – Ampere
@mutex'AnsiString'不仅仅是一个字节数组。它还有一个相关的代码页,这就是当在传递'AnsiString'到'TIdEncoderMIME.EncodeString()''时传递'AnsiString'值时会导致二进制数据丢失/损坏的原因。另外,如果您需要将代码迁移到移动设备,则“AnsiString”不可用(没有第三方修补程序) –