Java Base64解码结果意外不同

mik*_*gto 1 java base64

我有一个透明的1x1 GIF文件,其中包含以下数据:

$ xxd pixel.gif
00000000: 4749 4638 3961 0100 0100 f000 0000 0000  GIF89a..........
00000010: 0000 0021 f904 0100 0000 002c 0000 0000  ...!.......,....
00000020: 0100 0100 0002 0244 0100 3b              .......D..;
Run Code Online (Sandbox Code Playgroud)

该文件的Base64编码数据如下:

$ openssl base64 -in pixel.gif
R0lGODlhAQABAPAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==
Run Code Online (Sandbox Code Playgroud)

如果我解码此字符串,则会得到以下正确输出:

$ echo 'R0lGODlhAQABAPAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==' | openssl base64 -d | xxd
00000000: 4749 4638 3961 0100 0100 f000 0000 0000  GIF89a..........
00000010: 0000 0021 f904 0100 0000 002c 0000 0000  ...!.......,....
00000020: 0100 0100 0002 0244 0100 3b
Run Code Online (Sandbox Code Playgroud)

当尝试用Java解码此字符串时,我得到了意外的结果。考虑以下示例Java程序:

$ xxd pixel.gif
00000000: 4749 4638 3961 0100 0100 f000 0000 0000  GIF89a..........
00000010: 0000 0021 f904 0100 0000 002c 0000 0000  ...!.......,....
00000020: 0100 0100 0002 0244 0100 3b              .......D..;
Run Code Online (Sandbox Code Playgroud)

当我将编码的字符串传递到该程序时,我得到以下结果

$ echo 'R0lGODlhAQABAPAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==' | java Decode | xxd
00000000: 4749 4638 3961 0100 0100 efbf bd00 0000  GIF89a..........
00000010: 0000 0000 0021 efbf bd04 0100 0000 002c  .....!.........,
00000020: 0000 0000 0100 0100 0002 0244 0100 3b    ...........D..
Run Code Online (Sandbox Code Playgroud)

我可以在第11个字节看到对的预期0xf0更改输出0xef。现在,整个二进制字符串的长度为47个字节,而不是43个字节。为什么Java会发生这种情况?

kni*_*ttl 5

您不能将任意二进制数据转换为UTF-8字符串。UTF-8是遵循某些规则的unicode编码(例如,所有多字节序列必须以11或10作为高位开头,并且多字节序列的第一个字节告诉解码器此多字节序列中包含多少个字节)

您真正想要的是直接编写字节数组,而不是先将其转换为String:

byte[] data = Base64.getDecoder().decode(line.getBytes());
System.out.write(data);
Run Code Online (Sandbox Code Playgroud)