Как читать .NET Guid в Java UUID - PullRequest
20 голосов
/ 21 апреля 2011

Мне нужно сообщить Guid, сгенерированный в .NET, приложению 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;
}

Однако, когда я проверяю UUID с помощью toString(), Java UUID отличается от .NET Guid.

Например, .NET Guid

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

превращается в Java UUID

c2948788-ce65-e14d-aa15-75a11342bc63

Похоже, что порядок байтов первых трех групп меняется на противоположный, тогда как порядок в последних двух группах одинаков.

Так как я ожидал бы, что toString() как Guid, так и UUID даст одинаковый результат, кто-нибудь знает, как мне правильно читать .NET Guid в Java UUID?

Редактировать: Для пояснения, реализация не моя. Это закрытый конструктор класса java.util.UUID, который принимает byte[], который я скопировал, чтобы использовать для чтения байта [] с диска в UUID.

Я не хочу использовать строки для хранения направляющих, так как я храню их много, и это кажется пустой тратой.

Ссылка Рассела Тройвеста, по крайней мере, проясняет, почему первая пара групп Гуида перевернулась, а вторая половина остается в том же порядке. Вопрос в том, могу ли я .NET всегда генерировать эти байты в одном и том же порядке?

Ответы [ 7 ]

11 голосов
/ 14 апреля 2012

Редактировать 2017-08-30 : поменять местами элементы массива 6 и 7 для комментариев.

Мне нужно читать и записывать направляющие из / в MySQL (хранится как двоичный файл (16))в приложении C #, но база данных также используется приложениями 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);
    }
}
11 голосов
/ 21 апреля 2011

Не могли бы вы просто сохранить .Net Guid в виде строки и прочитать его в Java?Таким образом, вам не нужно беспокоиться о порядке следования байтов или о чем-либо.

Если нет, то это объясняет, как байты расположены в C #

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

7 голосов
/ 21 апреля 2011

В ответ на ваши изменения нет, вы не можете постоянно зависеть от байтов, генерируемых в том же порядке.Время выполнения определяет порядок байтов.Однако C # действительно предлагает BitConverter.isLittleEndian по этой самой причине.

Я знаю, что вы не можете изменить порядок байтов реализации Java и сдвиг битов.Но вы можете сдвинуть биты на стороне C # после сохранения и перед отправкой их в Java.

Обновление:

Статья MSDN по IsLittleEndian

Редактировать: Чтобы быть практичным, вы можете ДЕЙСТВИТЕЛЬНО рассчитывать на то, что он всегда имеет порядок байтов при размещении первого фрагмента байтов, но технически вы не можете.

5 голосов
/ 03 декабря 2011

GUID.toByteArray довольно странный в C #. Первая половина находится в порядке с прямым порядком байтов, а вторая половина - с большой частью.

Комментарий на этой странице отмечает этот факт: http://msdn.microsoft.com/en-us/library/system.guid.tobytearray.aspx

порядок байтов в возвращенном байтовом массиве отличается от строкового представления значения Guid. Порядок начальной четырехбайтовой группы и следующих двух двухбайтовых групп меняется на противоположный, тогда как порядок последней двухбайтовой группы и закрывающей шестибайтовой группы одинаков.

4 голосов
/ 20 февраля 2015

Как уже отмечалось, двоичное кодирование GUID в .NET имеет байты в первых трех группах, расположенные в порядке с прямым порядком байтов (обратный порядок) - см. Метод 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());
}
2 голосов
/ 21 апреля 2011

Я думаю, что ваша проблема здесь в том, что .NET является прямым порядком байтов, но JAVA является прямым порядком байтов , поэтому, когда вы читаете 128-битное целое число (GUID), написанное приложением C #, из приложения JAVA Вы должны сделать де преобразование из порядкового номера в обратный порядок.

0 голосов
/ 11 февраля 2015

Этот код работает для меня.

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)
...