Подтвердить что ты не робот

Как читать .NET Guid в Java UUID

Мне нужно передать Guid, который был сгенерирован в .NET для Java-приложения. Я использую Guid.ToByteArray() для хранения его на диске как byte[], затем прочитайте его в Java и преобразуйте его в UUID. Для этого я скопировал реализацию (private) конструктора 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(), UUID Java отличается от .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.

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

Ссылка Russell Troywest, по крайней мере, разъясняет, почему первые пары групп Guid выходят в обратном направлении, а вторая половина остается в том же порядке. Вопрос в том, могу ли я зависеть от .NET всегда, генерируя эти байты в том же порядке?

4b9b3361

Ответ 1

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

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

Update:

Статья MSDN на IsLittleEndian

Изменить: Чтобы быть практичным, вы можете ВЕРОЯТНО рассчитывать на то, что он всегда мало ориентирован по своему расположению первого фрагмента байтов, но технически вы не можете.

Ответ 2

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

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

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

Ответ 3

Изменить 2017-08-30. Поменял элементы массива 6 и 7 на каждый комментарий.

Мне нужно читать и писать гиды из/в MySQL (хранящиеся как двоичные (16)) в приложении С#, но база данных также используется Java-приложениями. Вот методы расширения, которые я использую для преобразования между порядком байтов большого и младшего порядка в формате .NET:

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

Ответ 4

GUID.toByteArray довольно странно в С#. Первая половина находится в малой степени, а вторая половина - в большой эндемии.

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

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

Ответ 5

Как уже отмечалось, двоичное кодирование 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());
}

Ответ 6

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

Ответ 7

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

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)

Ответ 8

В UuidUtil есть метод, который делает это, если кому-то еще это нужно.

UUID uuid = UuidUtil.fromMssqlGuidToUuid(guid);

Другой метод делает обратное.

UUID guid = UuidUtil.fromUuidToMssqlGuid(uuid);

https://github.com/f4b6a3/uuid-creator