2011-03-02 80 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更節省空間。