我想做以下...
a) 将生成的 UUID 压缩为长度为 8 的字符串。
b) 将压缩后的 UUID 解压回原来的 UUID。
原因是因为我必须将 UUID 发送到合作系统,而合作系统只接受 8 个字符的 UUID,并且我不能请求更改合作系统。
因此,剩下要做的就是将我必须的 UUID 压缩为 8 个字符字符串,然后在从合作系统返回消息时将其解压缩回原始 UUID。
有任何想法吗?
谢谢。
由于信息论的原因,您所问的内容是不可能的。
RFC 4122指定的 UUID是 128 位,UUID
Java 中的对象也是如此。
JavaString
可以为每个字符存储 16 位,这将构成一个 8char
字符串。但是,并非所有位序列都是有效的 UTF-16 字符串,因此在 8 个字符中您可以存储少于 128 位的信息。
因此,如果将 UUID 压缩为有效的 8 字符字符串,则会丢失信息,因此通常无法将其解压缩以取回原始 UUID。
您可能打算生成一个较短的字符串以用作唯一标识符。如果是这样,请参阅仅生成 8 个字符的 UUID。
实现 url 安全 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==
您可以将 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]
);
}
这段代码确实看起来应该可以工作(在这里自己尝试),并且可以使用 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。有关更多信息,请参阅上面的机械蜗牛的回应。
您可以始终如一地从通过UUID.randomUUID生成的编码 UUID中删除的唯一数据是用于 (always ) 的 2 位和用于( always ) 的 4 位。variant
2
version
4
这些全局标识符存在不同的变体。此类的方法用于操作 Leach-Salz 变体,尽管构造函数允许创建 UUID 的任何变体(如下所述)。
变体 2 (Leach-Salz) UUID 的布局如下: 最重要的 long 由以下无符号字段组成:
0xFFFFFFFF00000000 time_low
0x00000000FFFF0000 time_mid
0x000000000000F000 version
0x0000000000000FFF time_hi最不重要的 long 由以下无符号字段组成:
0xC000000000000000 variant
0x3FFF000000000000 clock_seq
0x0000FFFFFFFFFFFF node变体字段包含一个标识布局的值
UUID
。上述位布局仅对UUID
变量值为 2 的 a 有效,表示Leach-Salz变量。version 字段包含一个描述 this 类型的值
UUID
。UUID 有四种不同的基本类型:基于时间、DCE 安全、基于名称和随机生成的 UUID。这些类型的版本值分别为 1、2、3 和 4。