我想做以下事情......
a)将生成的UUID压缩为长度为8的字符串。
b)将压缩的UUID解压缩回原始UUID。
原因是我必须将UUID发送到合作伙伴系统,并且合作伙伴系统只接受UUID的8个字符,并且我不能请求更改合作伙伴系统。
所以,剩下的工作就是将UUID压缩到8个char字符串,然后在从伙伴系统返回消息时将其解压缩回原始UUID。
有什么想法吗?
感谢。
答案 0 :(得分:7)
出于信息理论的原因,你所要求的是不可能的。
RFC 4122指定的UUID为128位,UUID
objects in Java也是如此。
Java String
可以为每个字符存储16位,将为8 - char
字符串创建。但是,并非所有位序列都是有效的UTF-16字符串,因此在8个字符中,您可以存储少于128位的信息。
因此,如果您将UUID压缩为有效的8个字符的字符串,则会丢失信息,因此通常无法将其解压缩以检索原始UUID。
您可能希望生成一个较短的字符串以用作唯一标识符。如果是,请参阅Generating 8-character only UUIDs。
答案 1 :(得分:2)
实现url safe uuid压缩的最佳方法是在base64中对其进行编码
public class UUIDUtils {
public static String compress(UUID uuid) {
ByteBuffer bb = ByteBuffer.allocate(Long.BYTES * 2);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
byte[] array = bb.array();
return Base64.getEncoder().encodeToString(array);
}
public static UUID decompress(String compressUUID) {
ByteBuffer byteBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(compressUUID));
return new UUID(byteBuffer.getLong(), byteBuffer.getLong());
}
}
结果:6227185c-b25b-4497-b821-ba4f8d1fb9a1 - > YicYXLJbRJe4IbpPjR + 5oQ ==
答案 2 :(得分:0)
您可以将UUID转换为字符串,该字符串实际上是一个16位char
8个元素的序列,具体如下。
static String encodeUuid(final UUID id) {
final long hi = id.getMostSignificantBits();
final long lo = id.getLeastSignificantBits();
return new String(new char[] {
(char) ((hi >>> 48) & 0xffff), (char) ((hi >>> 32) & 0xffff),
(char) ((hi >>> 16) & 0xffff), (char) ((hi ) & 0xffff),
(char) ((lo >>> 48) & 0xffff), (char) ((lo >>> 32) & 0xffff),
(char) ((lo >>> 16) & 0xffff), (char) ((lo ) & 0xffff)
});
}
static UUID decodeUuid(final String enc) {
final char[] cs = enc.toCharArray();
return new UUID(
(long) cs[0] << 48 | (long) cs[1] << 32 | (long) cs[2] << 16 | (long) cs[3],
(long) cs[4] << 48 | (long) cs[5] << 32 | (long) cs[6] << 16 | (long) cs[7]
);
}
这段代码看起来确实应该可以工作(自己试试here),并且可以使用UTF-8和UTF-16进行编码/解码,而且大部分时间都没有问题:
static boolean validate(final UUID id, final Charset cs) {
final ByteBuffer buf = cs.encode(encodeUuid(id));
final UUID _id = decodeUuid(cs.decode(buf).toString());
return id.equals(_id);
}
public static void main(final String[] argv) {
final UUID id = UUID.randomUUID();
assert validate(id, StandardCharsets.UTF_8) : "failed using utf-8";
assert validate(id, StandardCharsets.UTF_16) : "failed using utf-16";
}
C:\dev\scrap>javac UuidTest.java
C:\dev\scrap>java -ea UuidTest
但确实存在一些UTF-16代码点被保留为代理的问题。如果发生这种情况,编码将无法正常工作,您将无法重建原始UUID。有关详细信息,请参阅上面的Mechanical snail的回复。
您可以通过UUID.randomUUID生成的编码UUID始终实际删除的唯一数据是variant
(始终为2
)和4用于version
的位(始终为4
)。
这些全局标识符存在不同的变体。此类的方法用于操作Leach-Salz变体,尽管构造函数允许创建任何UUID变体(如下所述)。
变体2(Leach-Salz)UUID的布局如下:最重要的长度包括以下无符号字段:
0xFFFFFFFF00000000 time_low
0x00000000FFFF0000 time_mid
0x000000000000F000 version
0x0000000000000FFF time_hi最不重要的长整数由以下无符号字段组成:
0xC000000000000000 variant
0x3FFF000000000000 clock_seq
0x0000FFFFFFFFFFFF node变体字段包含一个标识
UUID
布局的值。上述位布局仅对变量值为2的UUID
有效,表示 Leach-Salz 变体。版本字段包含一个描述此
UUID
类型的值。 UUID有四种不同的基本类型:基于时间,DCE安全性,基于名称和随机生成的UUID。这些类型的版本值分别为1,2,3和4.