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

让“awids”为base 64中的12个字符长度id(A-Z a-z 0-9“ – ”“@”).这是输入.

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

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

使用下面提供的可重现的示例,输出是错误的,因为在decode() – encode()之后没有返回输入字符串并且未保留双射(Q39s / L和Q39s / A映射到相同的值).

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

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

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

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

如果您选择可投影到整数个单位的输入大小,则可以使用Base64编码作为双射映射.显然,六个源字节可以编码为八个Base64编码的字节.但它不适用于六个编码字节.有趣的是,它将适用于您实际需要的大小,因为九个源字节将被编码为正好十二个编码字节:9×8 = 72,72 / 6 = 12.

点赞