Delphi 将[array of byte]分配给没有Unicode转换的变量
考虑以下代码段(在Delphi XE2中):Delphi 将[array of byte]分配给没有Unicode转换的变量,delphi,type-conversion,delphi-xe2,variant,ansistring,Delphi,Type Conversion,Delphi Xe2,Variant,Ansistring,考虑以下代码段(在Delphi XE2中): Base64Val是编码为Base64的二进制值(因此没有null字节)。(OleVariant)结果将在客户端应用程序和DataSnap服务器之间自动编组和发送 当我用Wireshark捕获流量时,我看到StrVal和Base64Val都作为Unicode字符串传输。如果可以,我希望避免对Base64Val进行Unicode转换。我查看了所有的Variant类型,除了varString之外,没有任何其他类型可以传输字符数组 我发现它显示了如何创建一
Base64Val
是编码为Base64的二进制值(因此没有null
字节)。(OleVariant
)结果将在客户端应用程序和DataSnap服务器之间自动编组和发送
当我用Wireshark捕获流量时,我看到StrVal
和Base64Val
都作为Unicode字符串传输。如果可以,我希望避免对Base64Val
进行Unicode转换。我查看了所有的Variant
类型,除了varString
之外,没有任何其他类型可以传输字符数组
我发现它显示了如何创建一个变量字节数组。我想我可以使用这种技术,而不是使用
ansisting
。不过我很好奇,有没有另一种方法可以在不转换为Unicode字符串的情况下将非Unicode字符数据数组分配给变量?Delphi的实现支持使用自定义变量类型代码在变量中存储AnsiString和UnicodeString。这些代码是varString和varUString
但是interop通常使用标准的OLE变体,OLE字符串varOleStr是16位编码的。这似乎就是你观察的原因
如果希望避免转换为16位文本,则需要将数据作为字节数组放入。这样做会使base64编码毫无意义。停止base64对有效负载进行编码,并以字节数组的形式发送二进制文件。与问题中的示例保持一致,这就是我如何使其工作的(使用问题中引用的另一个问题的代码和注释): 然后在DataSnap服务器上,我可以像这样从OleVariant中提取二进制数据,假设OleVariant中的变量数组中的
Value
是Result[1]
:
procedure GetBinaryData(Value: Variant; Result: TMemoryStream);
var
SafeArray: PVarArray;
begin
SafeArray := VarArrayAsPSafeArray(Value);
Assert(SafeArray.ElementSize=1);
Result.Clear;
Result.WriteBuffer(SafeArray.Data^, SafeArray.Bounds[0].ElementCount);
end;
“这些代码是varString和varUString。”-AFAIR,表示短字符串。对于AnsiString,有varLString//PS:如果二进制流由于任何原因不可行,而base64也不可行,那么还有yEnc编码heavy@Arioch不,那些是长串的,让它工作吧。它通过PVarray发送二进制数据,在OleVariant中进行编组,而不使用Base64。我将分别发布答案,包括大卫的另一个答案,在那里他展示了如何做大部分工作。这里有一点不对称。代码的第一部分包括
SizeOf()
,但第二部分没有。这两者都不是必需的,因为您知道元素是大小为1的字节。但是您可能应该在第二个代码块中添加一些健全性检查,因为编译器无法保证变量数组的内容+1并且感谢您先前已删除的关于为什么有价值的解释的评论。我确实试过了,我很高兴你注意到了。:-)谢谢@David-我一直很感谢你花时间解释原因。我尝试按照您的建议添加SizeOf()
,但不知道如何访问SafeArray.Data
的元素。所以我在两者中添加了SizeOf(Byte)
(为了保持一致)。虽然,这也不是完美的…你介意我编辑你的答案来显示我认为你应该做什么吗?这比试图解释要容易得多。你的问题是关于解释器的,你的答案是关于解释器的。也许我错过了什么…@Arioch'The实际上只是一个字节数组编组问题
function PrepData(StrVal: string; Data: TBytes): OleVariant;
var
SafeArray: PVarArray;
begin
Result := VarArrayCreate([0, 1], varVariant);
Result[0] := StrVal;
Result[1] := VarArrayCreate([1, Length(Data)], varByte);
SafeArray := VarArrayAsPSafeArray(Result[1]);
Move(Pointer(Data)^, SafeArray.Data^, Length(Data));
end;
procedure GetBinaryData(Value: Variant; Result: TMemoryStream);
var
SafeArray: PVarArray;
begin
SafeArray := VarArrayAsPSafeArray(Value);
Assert(SafeArray.ElementSize=1);
Result.Clear;
Result.WriteBuffer(SafeArray.Data^, SafeArray.Bounds[0].ElementCount);
end;