2011-03-02 89 views
4

我目前正在研究MongoDb作为一​​个可能的数据库选项,而且我在处理Guid序列化时遇到了问题。起初我认为这可能是C#驱动程序序列化中的一个错误,但现在我认为这更可能是我的天真假设。base64指导base64

要帮我转换BSON的base64表示来回的GUID,我写了几个小的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 
MongoDB shell version: 1.6.5 
connecting to: test 
> b = new BinData(3, "ASfjU2OYEd69ZgAVF4pePA=="); 
BinData(3,"ASfjU2OYEd69ZgAVF4pePA==") 
> b.hex(); 
127e353639811debd66015178a5e3c 
> 

因此,大家可以看到,我的Guid得到b ack与我输入的内容不匹配。我的函数和hex()返回相同的内容。如果你原来的比较结果:

53E32701-9863-DE11-BD66-0015178A5E3C
0127e353-6398-11de-bd66-0015178a5e3c

你可以看到第3套六角对反转,但最后2套不是。这让我觉得有一些关于Guid.ToString(),我不明白。

任何人都可以教育我吗?

+0

这是什么语言? – 2011-03-02 19:11:59

+0

这些脚本位于Powershell中。我使用该字符串的原因是因为我无法弄清楚如何使用-ArgumentList传递字节数组。 – 2011-03-02 19:26:16

+0

这就是我错过的神奇逗号。每天学些新东西。 – 2011-03-02 19:34:30

回答

12

GUID中的字节顺序与小端系统上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维基百科看看更多的细节。

您将会看到大部分数据存储在“本地”字节序中......这是混淆来自何处。

引述:

数据4存储字节所显示的GUID文本编码相同的顺序(见下文),但其他三场是在小端系统逆转(例如英特尔CPU )。


编辑:

Powershell的版本:

function base64toguid 
{ 
    param($str); 
    $b = [System.Convert]::FromBase64String($str); 
    $g = new-object -TypeName System.Guid -ArgumentList (,$b); 
    return $g; 
} 

作为一个额外的警告,你可以选择剪掉你的字符串末尾的 “==”,因为它只是填充(如果您尝试节省空间,这可能会有所帮助)。

+0

那么Guid.ToByteArray如UUID RFC中所指定的那样返回Big-endian中的字节?似乎就是这个意思。我想知道为什么MSFT不只是在内部表现这种方式。 – 2011-03-02 19:40:53

+0

它可能*是*代表那种方式*内部*。但是,当你解析它时,它会使用Data1到Data3的CPU的native-endian-ness。 – 2011-03-02 19:43:49

+0

哦,男人,endian问题使我的大脑疼痛。这让我想起了解析WAV文件的地方,它们混合了大小写字母。感谢您的快速回答。 – 2011-03-02 19:52:07

2

您需要调用带有字节数组的Guid构造函数。有在PowerShell中需要特殊语法 - 如果你只是传递$ B,它会告诉你它找不到一个构造函数16个参数,所以你必须包装在另一个数组的字节数组:

$g = new-object -TypeName System.Guid -ArgumentList (,$b) 
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,然后直接转换为二进制文件的工作量要少得多(例如,注意不会有endian问题)。此外,数据将以二进制形式存储在服务器上,因此它比使用base64更节省空间。