How to read a .NET Guid into a Java UUID
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?
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.
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
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);
}
}
链接地址: http://www.djcxy.com/p/91474.html
上一篇: 在MySQL中存储UUID v4