【问题标题】:How to read a .NET Guid into a Java UUID如何将 .NET Guid 读入 Java UUID
【发布时间】:2011-08-10 08:55:19
【问题描述】:

我需要将 .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。

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

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

【问题讨论】:

  • 看起来您以错误的方式移动位。为什么要尝试让它变得可爱呢?读取字节并首先进行适当的分配(首先使用索引),然后使用移位运算符进行优化(如有必要)。关键是要有易于理解的代码。
  • Java 严格按照 Big Endian 存储数据,而 C# 没有指定“endianness”,但通常将数据存储为 Little Endian。就像@casperOne 说的那样,你换错了方向。
  • 我一直在尝试对使用这种结构的框架进行逆向工程。一直盯着奇怪的位移两个多小时,直到我找到了这个帖子。

标签: c# java .net guid uuid


【解决方案1】:

编解码器 DotNetGuid1CodecDotNetGuid4Codec 可以将 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

【讨论】:

    【解决方案2】:

    如前所述,.NET 中 GUID 的二进制编码在前三组中的字节以 little-endian 顺序(反向)放置 - 请参阅Guid.ToByteArray Method。要从中创建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());
    }
    

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 我不确定这是否是 java 特有的东西,但我需要翻转活动目录 guid / nativeGuid 的字节序,并且使用此代码会产生错误。修复是在代码中没有的最后两个字节交换:java[6]=net[7]; java[7]=网络[6];另请注意,这两种方法是相同的,您可以将其简化为一个翻转功能。
      • 所以你是说应该交换这两个字节而不是net[6] = java[6]net[7] = java[7]?我知道这段代码对我在 MySQL 中处理 Guid 有用(现在手头没有那个数据库),但 @Russell Troywest 下面的答案可能是更安全的选择。
      • 这就是 Active Directory 的工作方式。奇怪的东西!我基本上是在 DirectoryEntry.Guid 和 DirectoryEntry.NativeGuid 之间切换,使用您的代码进行修改。根据Guids的文档,最后一个字节应该根据我对该文本的基本理解进行交换
      • 您的net[6] = java[6]; 代码中似乎有错字(或错误),应该是net[6] = java[7]; 吗?
      • 我不得不在 ToBigEndian 中将 net[7] 转换为 6,将 net[6] 转换为 7
      【解决方案4】:

      GUID.toByteArray 在 C# 中非常奇怪。前半部分是little-endia,后半部分是big-endia。

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

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

      【讨论】:

      • @Marc Gravell 注意到的“疯狂的字节序”
      【解决方案5】:

      此代码对我有用。

      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)
      

      【讨论】:

        【解决方案6】:

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

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

        更新:

        MSDN Article on IsLittleEndian

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

          • 我认为 C# 字节序在技术上是由运行时决定的,并且在大多数 CLR 实现中恰好是小字节序。要真正彻底,总是有IsLittleEndian 之类的。但这也可能是问题的来源。至少这是我的猜测。
          【解决方案8】:

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-11
            • 1970-01-01
            • 1970-01-01
            • 2010-10-06
            相关资源
            最近更新 更多