如何使用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)BytesTMemoryStream

你不可错过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; 
+0

感谢。我将我的代码转换为使用TIDBytes。有用。但有一个问题:为什么不应该使用AnsiString来存储二进制数据? AnsiString只不过是一个字节数组而已。只要你不把它转换成字符串,一切都应该没问题。 – Ampere

+0

@mutex'AnsiString'不仅仅是一个字节数组。它还有一个相关的代码页,这就是当在传递'AnsiString'到'TIdEncoderMIME.EncodeString()''时传递'AnsiString'值时会导致二进制数据丢失/损坏的原因。另外,如果您需要将代码迁移到移动设备,则“AnsiString”不可用(没有第三方修补程序) –