如何将 .NET Guid 读入 Java UUID

问题描述 投票:0回答:9

我需要将 .NET 中生成的 Guid 传递给 Java 应用程序。我使用

Guid.ToByteArray()
将其作为
byte[]
存储在磁盘上,然后将其读入 Java 并将其转换为 UUID。为此,我复制了 UUID 的(私有)构造函数的实现,该构造函数采用
byte[]
:

private UUID(byte[] data) {
    long msb = 0;
    long lsb = 0;
    assert data.length == 16;
    for (int i=0; i<8; i++)
        msb = (msb << 8) | (data[i] & 0xff);
    for (int i=8; i<16; i++)
        lsb = (lsb << 8) | (data[i] & 0xff);
    this.mostSigBits = msb;
    this.leastSigBits = lsb;
}

但是,当我使用

toString()
检查 UUID 时,Java UUID 与 .NET Guid 不同。

例如,.NET Guid

888794c2-65ce-4de1-aa15-75a11342bc63

变成Java UUID

c2948788-ce65-e14d-aa15-75a11342bc63

看起来前三组的字节顺序颠倒了,而后两组的顺序是相同的。

由于我希望 Guid 和 UUID 的

toString()
产生相同的结果,有谁知道我应该如何正确地将 .NET Guid 读入 Java UUID?

编辑:澄清一下,实施不是我自己的。它是

java.util.UUID
类的私有构造函数,它采用
byte[]
,我将其复制以用于将 byte[] 从磁盘读取到 UUID。

我不想使用字符串来存储指南,因为我存储了很多指南,这似乎浪费空间。

Russell Troywest 的链接至少澄清了为什么 Guid 的前几组结果相反,而后半部分保持相同的顺序。问题是,我可以依赖 .NET always 以相同的顺序生成这些字节吗?

c# java .net guid uuid
9个回答
13
投票

您不能将 .Net Guid 存储为字符串并将其读入 Java 中吗?这样你就不需要担心字节顺序或任何事情。

如果不是,那么这解释了 C# 中字节是如何布局的

http://msdn.microsoft.com/en-us/library/fx22893a.aspx


12
投票

编辑 2017-08-30:每个评论交换了数组元素 6 和 7。

我必须在 C# 应用程序中从 MySQL(存储为二进制 (16))读取和写入 Guid,但该数据库也由 Java 应用程序使用。以下是我用于在 .NET 小端字节顺序和 Java 大端字节顺序之间转换的扩展方法:

public static class GuidExtensions
{
    /// <summary>
    /// A CLSCompliant method to convert a Java big-endian Guid to a .NET 
    /// little-endian Guid.
    /// The Guid Constructor (UInt32, UInt16, UInt16, Byte, Byte, Byte, Byte,
    ///  Byte, Byte, Byte, Byte) is not CLSCompliant.
    /// </summary>
    [CLSCompliant(true)]
    public static Guid ToLittleEndian(this Guid javaGuid) {
        byte[] net = new byte[16];
        byte[] java = javaGuid.ToByteArray();
        for (int i = 8; i < 16; i++) {
            net[i] = java[i];
        }
        net[3] = java[0];
        net[2] = java[1];
        net[1] = java[2];
        net[0] = java[3];
        net[5] = java[4];
        net[4] = java[5];
        net[6] = java[7];
        net[7] = java[6];
        return new Guid(net);
    }

    /// <summary>
    /// Converts little-endian .NET guids to big-endian Java guids:
    /// </summary>
    [CLSCompliant(true)]
    public static Guid ToBigEndian(this Guid netGuid) {
        byte[] java = new byte[16];
        byte[] net = netGuid.ToByteArray();
        for (int i = 8; i < 16; i++) {
            java[i] = net[i];
        }
        java[0] = net[3];
        java[1] = net[2];
        java[2] = net[1];
        java[3] = net[0];
        java[4] = net[5];
        java[5] = net[4];
        java[6] = net[7];
        java[7] = net[6];
        return new Guid(java);
    }
}

12
投票

如前所述,.NET 中 GUID 的二进制编码的前三组中的字节以小端顺序(相反)放置 - 请参阅Guid.ToByteArray 方法。要从中创建

java.util.UUID
,您可以使用以下代码:

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;

public UUID toUUID(byte[] binaryEncoding) {
    ByteBuffer source = ByteBuffer.wrap(binaryEncoding);
    ByteBuffer target = ByteBuffer.allocate(16).
        order(ByteOrder.LITTLE_ENDIAN).
        putInt(source.getInt()).
        putShort(source.getShort()).
        putShort(source.getShort()).
        order(ByteOrder.BIG_ENDIAN).
        putLong(source.getLong());
    target.rewind();
    return new UUID(target.getLong(), target.getLong());
}

7
投票

根据您的编辑,不,您不能始终依赖于以相同顺序生成的字节。运行时决定字节顺序。然而,出于这个原因,C# 确实提供了

BitConverter.isLittleEndian

我知道你无法改变 Java 实现的字节顺序和位移位。但您可以在存储之后、将它们发送到 Java 之前在 C# 端移动这些位。

更新:

MSDN 关于 IsLittleEndian 的文章

编辑: 实际上,您可能可以指望它在第一个字节块的布局中始终是小尾数,但从技术上讲您不能。


5
投票

GUID.toByteArray 在 C# 中相当奇怪。前半部分为小端,后半部分为大端。

此页面上的评论指出了这一事实: http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx

返回的字节数组中的字节顺序与 Guid 值的字符串表示形式不同。开始的四字节组和接下来的两个两字节组的顺序相反,而最后一个两字节组和结束的六字节组的顺序相同。


3
投票

我认为你的问题是.NET是小端字节序,而JAVA是大端字节序,所以当你从JAVA应用程序读取由C#应用程序编写的128位整数(GUID)时,你必须进行de转换从小端到大端。


1
投票

编解码器

DotNetGuid1Codec
DotNetGuid4Codec
可以将 UUID 编码为 .Net Guid。

// Convert time-based (version 1) to .Net Guid
UuidCodec<UUID> codec = new DotNetGuid1Codec();
UUID guid = codec.encode(timeUuid);
// Convert random-based (version 4) to .Net Guid
UuidCodec<UUID> codec = new DotNetGuid4Codec();
UUID guid = codec.encode(randomUuid);

参见:uuid-creator


0
投票

此代码对我有用。

var msb: Long = 0
var lsb: Long = 0
for(i <- Seq(3, 2, 1, 0, 5, 4, 7, 6)) {
  msb = (msb << 8) | (data(i) & 0xFF)
}
for(i <- 8 until 16) {
  lsb = (lsb << 8) | (data(i) & 0xFF)
}
new UUID(msb, lsb)

0
投票
public static Guid ToGuid(this JavaUUID self)
{
    var vec = Vector128.Shuffle(
        Vector128.Create(self.MostSigBits, self.LeastSigBits).AsByte(),
        Vector128.Create((byte)4, 5, 6, 7, 2, 3, 0, 1, 15, 14, 13, 12, 11, 10, 9, 8)
    );
    return Unsafe.As<Vector128<byte>, Guid>(ref vec);
}
© www.soinside.com 2019 - 2024. All rights reserved.