如何将 .NET Guid 读入 Java UUID

发布于 2024-11-02 20:52:09 字数 1183 浏览 5 评论 0 原文

我需要将 .NET 中生成的 Guid 传递给 Java 应用程序。我使用 Guid.ToByteArray() 将其作为 byte[] 存储在磁盘上,然后将其读入 Java 并将其转换为 UUID。为此,我复制了采用 byte[] 的 UUID 的(私有)构造函数的实现:

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 始终 以相同的顺序生成这些字节吗?

I need to communicate a Guid that was generated in .NET to a Java application. I use Guid.ToByteArray() to store it on disk as a byte[], then read it into Java and convert it to a UUID. For this purpose I copied the implementation of the (private) constructor of UUID that takes a 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;
}

However, when I inspect the UUID using toString(), the Java UUID is different from the .NET Guid.

For example, the .NET Guid

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

turns into the Java UUID

c2948788-ce65-e14d-aa15-75a11342bc63

It seems that the byte ordering of the first three groups is reversed, while the ordering in the last two groups is the same.

Since I would expect the toString() of both the Guid and the UUID to yield the same result, does anyone know how I should correctly read the .NET Guid into a Java UUID?

Edit: To clarify, the implementation is not my own. It is the private constructor of the java.util.UUID class that takes a byte[], which I copied to use for the purpose of reading a byte[] from disk into a UUID.

I do not want to use strings to store the Guids as I'm storing a lot of them and it seems like a waste of space.

Russell Troywest's link at least clarifies why the first couple of groups of the Guid come out reversed, while the second half stays in the same order. The question is, can I depend on .NET always generating these bytes in the same order?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

面如桃花 2024-11-09 20:52:09

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

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

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

Could you not just store the .Net Guid as a string and read it into Java? That way you don't need to worry about byte order or anything.

If not then This explains how the bytes are laid out in C#

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

终止放荡 2024-11-09 20:52:09

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

我必须阅读&在 C# 应用程序中将 Guid 写入 MySQL(存储为二进制 (16)),但 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);
    }
}

Edit 2017-08-30: Swapped array elements 6 and 7 per comments.

I have to read & write Guids from/to MySQL (stored as binary(16)) in a C# app, but the database is also used by Java apps. Here are the extension methods I use for converting between .NET little-endian and Java big-endian byte order:

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);
    }
}
凶凌 2024-11-09 20:52:09

如前所述,.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());
}

As already noted, the binary encoding of GUID in .NET has bytes in the first three groups placed in the little-endian order (reversed) – see Guid.ToByteArray Method. To create java.util.UUID from it you can use the following code:

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());
}
绿阴红影里的.如风往事 2024-11-09 20:52:09

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

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

更新:

有关 IsLittleEndian 的 MSDN 文章

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

In response to your edit, no, you cannot consistently depend on the bytes being generated in the same order. The runtime determines the endianness. C# does however offer BitConverter.isLittleEndian for this very reason.

I know you can't change the endianness of the Java implementation and the bit shifting. But you can shift the bits on the C# end after storing and before sending them to Java.

Update:

MSDN Article on IsLittleEndian

Edit:
To be practical, you can PROBABLY count on it always being little endian in its layout of the first chunk of bytes, but technically you can't.

瞳孔里扚悲伤 2024-11-09 20:52:09

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

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

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

The GUID.toByteArray is pretty odd in C#. The first half are in little-endian and the second half are in big-endia.

A comment on this page notes this fact:
http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx

the order of bytes in the returned byte array is different from the string representation of a Guid value. The order of the beginning four-byte group and the next two two-byte groups is reversed, whereas the order of the last two-byte group and the closing six-byte group is the same.

画离情绘悲伤 2024-11-09 20:52:09

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

I think your problem here is that .NET is little-endian but JAVA is big-endian, so when you read a 128 bits integer (a GUID) written by a C# app from a JAVA app you have to do de conversion from little-endian to big-endian.

樱花坊 2024-11-09 20:52:09

编解码器 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

The codecs DotNetGuid1Codec and DotNetGuid4Codec can encode UUIDs to .Net Guids.

// 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);

See: uuid-creator

紫竹語嫣☆ 2024-11-09 20:52:09

这段代码对我有用。

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)

This code works for me.

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)
冰魂雪魄 2024-11-09 20:52:09

使用simd加速版本

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);
}

public static JavaUUID ToJavaUUID(this Guid self)
{
    var vec = Vector128.Shuffle(
        Unsafe.As<Guid, Vector128<byte>>(ref self).AsByte(),
        Vector128.Create((byte)6, 7, 4, 5, 0, 1, 2, 3, 15, 14, 13, 12, 11, 10, 9, 8)
    ).AsUInt64();
    return new JavaUUID { MostSigBits = vec.GetElement(0), LeastSigBits = vec.GetElement(1) };
}

Use simd accelerated version

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);
}

public static JavaUUID ToJavaUUID(this Guid self)
{
    var vec = Vector128.Shuffle(
        Unsafe.As<Guid, Vector128<byte>>(ref self).AsByte(),
        Vector128.Create((byte)6, 7, 4, 5, 0, 1, 2, 3, 15, 14, 13, 12, 11, 10, 9, 8)
    ).AsUInt64();
    return new JavaUUID { MostSigBits = vec.GetElement(0), LeastSigBits = vec.GetElement(1) };
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文