Java 8 无法使用java.util.Base64正确编码和解码

Java 8 无法使用java.util.Base64正确编码和解码,java-8,base64,decode,encode,Java 8,Base64,Decode,Encode,将“awid”设为基数为64的12个字符长度的id(A-Z A-Z 0-9“-@”)。这是输入 我的最终目标是在这些awid和UUIDs之间创建一个双射映射,使用一些填充,将awid作为初始输入 在尝试使用java.util.Base64时,在再次解码和编码之后,我没有得到初始值。我犯的愚蠢错误是什么?:) 对于下面我给出的可再现示例,输出是错误的,因为输入字符串在decode()-encode()之后没有返回,并且双射没有保留(Q39s/L和Q39s/a都映射到相同的值) 请毫不犹豫地指出我在

将“awid”设为基数为64的12个字符长度的id(
A-Z A-Z 0-9“-@”
)。这是输入

我的最终目标是在这些awid和
UUID
s之间创建一个双射映射,使用一些填充,将awid作为初始输入

在尝试使用
java.util.Base64
时,在再次解码和编码之后,我没有得到初始值。我犯的愚蠢错误是什么?:)

对于下面我给出的可再现示例,输出是错误的,因为输入字符串在
decode()
-
encode()
之后没有返回,并且双射没有保留(
Q39s/L
Q39s/a
都映射到相同的值)


请毫不犹豫地指出我在代码中犯的任何其他错误,即使它们与问题没有直接关系。谢谢。

如果您将编码数据视为整字节(或ASCII字符)序列,则Base64编码不是所有输入大小的双射映射。Base64将八位的单位编码为六位的单位(每个单位产生64种可能的组合),因此当您编码四个字节时,换句话说
4×8=32
位,您将得到
32/6=5⅓单位输出,这意味着输出的第六个单位不会使用所有位

换句话说,当您将由64个已定义字符中的六个组成的任意字符串视为Base64编码时,您将投影一个64的字符串⁶ 组合到具有256个字节的六个字节的“源”序列⁴ 组合,这意味着数据丢失


如果您选择的输入大小可以投影到整数单位,则可以使用Base64编码作为双射映射,例如,显然,六个源字节可以编码为八个Base64编码字节。但它不适用于6个编码字节。有趣的是,它将适用于您实际需要的大小,因为九个源字节将被编码为十二个编码字节:
9×8=72
72/6=12
。非常感谢。我将把12个编码字符拆分为8+4个字符,这将使我得到6个字节(msb)+3个字节(lsb)。在发布问题后清除我找到的资源(是的,我知道我应该从它开始)
------------------------------------------> Q39s/L (6 [51 33 39 73 2f 4c]) 
    4 [43 7f 6c fc] -> 6 [51 33 39 73 2f 41] -> Q39s/A (6 [51 33 39 73 2f 41]) 
    4 [43 7f 6c fc] -> 6 [51 33 39 73 2f 41] -> Q39s/A (6 [51 33 39 73 2f 41])


    import java.nio.charset.StandardCharsets;
    import java.util.Base64;
    import java.util.StringJoiner;

    public class StackOverflowQuestion {

      public static void main(String[] args) {

        String halfAwid = "Q39s/L";

        byte[] sigBits = Base64.getDecoder().decode(halfAwid.getBytes(StandardCharsets.UTF_8));

        byte[] actualSigBits = Base64.getEncoder().withoutPadding().encode(sigBits);

        String actualHalfAwid = new String(actualSigBits, StandardCharsets.UTF_8);

        byte[] sigBits2 = Base64.getDecoder().decode(halfAwid.getBytes(StandardCharsets.UTF_8));
        byte[] actualSigBits2 = Base64.getEncoder().withoutPadding().encode(sigBits2);
        String actualHalfAwid2 = new String(actualSigBits2, StandardCharsets.UTF_8);

        System.out.println("----------------------------------------------> "
            + halfAwid + " (" + toHexString(halfAwid) + ") "
            + "\n"
            + "    "
            + toHexString(sigBits) + " -> "
            + toHexString(actualSigBits) + " -> "
            + actualHalfAwid + " (" + toHexString(actualHalfAwid) + ") "
            + "\n"
            + "    "
            + toHexString(sigBits2) + " -> "
            + toHexString(actualSigBits2) + " -> "
            + actualHalfAwid2 + " (" + toHexString(actualHalfAwid2) + ")"
            + "");
      }

      private static String toHexString(byte[] bytes) {
        StringJoiner joiner = new StringJoiner(" ", "" + bytes.length + " [", "]");
        for (byte b : bytes) {
          joiner.add(String.format("%02x", b));
        }
        return joiner.toString();
      }

      private static String toHexString(String text) {
        return toHexString(text.getBytes());
      }
    }