base64 to guid to base64

时间:2011-03-02 19:08:18

标签: powershell mongodb guid

我目前正在研究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()有一些我不明白的地方。

有人可以教育我吗?

3 个答案:

答案 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更节省空间。