我目前正在研究MongoDb作为可能的数据库选项,而且我在处理Guid序列化方面遇到了麻烦。我一开始认为这可能是C#驱动程序序列化中的一个错误,但现在我认为这更像是一个天真的假设。
为了帮助我将Bson base64表示来回转换为Guids,我写了几个小的powershell函数来帮助:
function base64toguid
{
param($str);
$b = [System.Convert]::FromBase64String($str);
$hex = "";
foreach ($x in $b) {
$hex += $x.ToString("x2");
}
$g = new-object -TypeName System.Guid -ArgumentList $hex;
return $g;
}
function guidtobase64
{
param($str);
$g = new-object -TypeName System.Guid -ArgumentList $str;
$b64 = [System.Convert]::ToBase64String($g.ToByteArray());
return $b64;
}
我遇到的问题的一个例子:
:) guidtobase64("53E32701-9863-DE11-BD66-0015178A5E3C");
ASfjU2OYEd69ZgAVF4pePA==
:) base64toguid("ASfjU2OYEd69ZgAVF4pePA==");
Guid
----
0127e353-6398-11de-bd66-0015178a5e3c
来自mongo shell:
:) mongo
MongoDB shell version: 1.6.5
connecting to: test
> b = new BinData(3, "ASfjU2OYEd69ZgAVF4pePA==");
BinData(3,"ASfjU2OYEd69ZgAVF4pePA==")
> b.hex();
127e353639811debd66015178a5e3c
>
所以你可以看到,我回来的Guid与我输入的内容不匹配。我的函数和hex()返回相同的东西。如果您将原始结果与结果进行比较:
53E32701-9863-DE11-BD66-0015178A5E3C
0127e353-6398-11de-bd66-0015178a5e3c
你可以看到前三组十六进制对是相反的,但最后两组不是。这让我觉得Guid.ToString()有一些我不明白的地方。
有人可以教育我吗?
答案 0 :(得分:13)
GUID中的字节顺序与little-endian系统上ToString()
表示中的顺序不同。
你应该使用guid.ToByteArray()而不是使用ToString()。
而且,您应该使用new Guid(byte[] b)
来构建它,而不是$str
。
用纯C#表示:
public string GuidToBase64(Guid guid)
{
return System.Convert.ToBase64String(guid.ToByteArray()); // Very similar to what you have.
}
public Guid Base64Toguid(string base64)
{
var bytes = System.Convert.FromBase64String(base64);
return new Guid(bytes); // Not that I'm not building up a string to represent the GUID.
}
查看维基百科上的"Basic Structure" section of the GUID article了解更多详情。
您将看到大多数数据都存储在“本机”字节序中......这就是混乱的来源。
引用:
Data4以与GUID文本编码中显示的顺序相同的方式存储字节(见下文),但在小端系统(例如Intel CPU)上反转其他三个字段。
<小时/>
Powershell版本:
function base64toguid
{
param($str);
$b = [System.Convert]::FromBase64String($str);
$g = new-object -TypeName System.Guid -ArgumentList (,$b);
return $g;
}
作为一个额外的警告,您可以选择修剪字符串末尾的“==”,因为它只是填充(如果您试图节省空间,这可能会有所帮助)。
答案 1 :(得分:2)
您需要调用带有字节数组的Guid构造函数。在Powershell中需要特殊的语法 - 如果你只传递$ b它将告诉你它找不到一个带有16个参数的构造函数,所以你必须将字节数组包装在另一个数组中:
$g = new-object -TypeName System.Guid -ArgumentList (,$b)
答案 2 :(得分:0)
查看mongo网站上的c-sharp driver documentation,结果发现为System.Guid提供了隐式转换。
所以在c#中(对不起,我的powershell有点生疏),你只需写:
Guid g = Guid.NewGuid(); //or however your Guid is initialized
BsonValue b = g;
我认为反过来也可能有效:
BsonValue b = // obtained this from somewhere
Guid g = b;
如果您没有特别需要将Guid序列化为base64,那么直接转换为二进制文件的工作要少得多(请注意,例如,没有端点问题)。此外,数据将以二进制形式存储在服务器上,因此它比使用base64更节省空间。