在 Java 中解码 Base64 数据
Posted
技术标签:
【中文标题】在 Java 中解码 Base64 数据【英文标题】:Decode Base64 data in Java 【发布时间】:2010-10-02 22:50:52 【问题描述】:我有一张经过 Base64 编码的图像。在 Java 中解码的最佳方法是什么?希望只使用 Sun Java 6 附带的库。
【问题讨论】:
无论您使用什么类型的应用程序(实验与否),它就像使用这里的代码在您的 utils 包中创建一个 Base64.java 文件一样简单:migbase64.sourceforge.net 看看性能图表并注意差异:快 4-5 倍。 仅供参考:JEP 135 建议在 Java 平台中为此引入一个标准的、可发现的 API。 进展情况:mail.openjdk.java.net/pipermail/core-libs-dev/2012-October/… 这是我最近一起完成的另一个实现:github.com/n1hility/playground/blob/master/src/main/java/org/… 请注意,如果您正在开发 android 应用,Google 已经这样做了:developer.android.com/reference/android/util/Base64.html 【参考方案1】:从 Java 8 开始,有一个官方支持的用于 Base64 编码和解码的 API。 随着时间的推移,这可能会成为默认选择。
API 包括类java.util.Base64
及其嵌套类。它支持三种不同的风格:基本、URL 安全和 MIME。
使用“基本”编码的示例代码:
import java.util.Base64;
byte[] bytes = "Hello, World!".getBytes("UTF-8");
String encoded = Base64.getEncoder().encodeToString(bytes);
byte[] decoded = Base64.getDecoder().decode(encoded);
documentation for java.util.Base64
包含更多用于配置编码器和解码器以及使用不同类作为输入和输出(字节数组、字符串、ByteBuffers、java.io 流)的方法。
【讨论】:
我正在使用 Java 8。如果使用 Java 8,这是推荐的方法吗? @JohnMerlino 如果不需要与旧 Java 版本兼容,我建议使用此 API,因为 JRE 比大多数库具有更强的兼容性策略。此外,由于包含在 JRE 中,它不会以任何可能的方式限制您的依赖关系。 Java 7 已停产,Java 9 即将到来,这就是我的正确答案! 差不多好:它只接受原始 base64 流,不接受 base64 文件。我不得不改用final byte[] decoded = Base64.getMimeDecoder().decode(encoded);
。不过还是谢谢! (commons-io FileUtils.readFileToByteArray
和 FileUtils.writeByteArrayToFile
很好——尤其是当您意识到 encoded
也可以是 byte[]
时。)【参考方案2】:
从 v6 开始,Java SE 附带 JAXB。 javax.xml.bind.DatatypeConverter
有静态方法可以让这一切变得简单。请参阅parseBase64Binary()
和printBase64Binary()
。
【讨论】:
但是,printBase64Binary(..)
方法似乎没有执行 Base64 的 MIME 版本(en.wikipedia.org/wiki/Base64#MIME),而私有 Sun 和 Commons 实现使用它。具体来说,对于大于 76 个字符的字符串,会添加换行符。我没有找到如何为此行为配置 JAXB 的实现... :-(
然而,sun 实现将忽略换行符。所以它们是兼容的。
警告! parseBase64Binary 将静默跳过无效字符,并且不会检查 base64 的有效性。最好使用 Commons Codec 或 Guava Base64。请注意,Guava 拒绝换行符和空格字符,因此您需要解析省略空格的字符串:BaseEncoding.base64().decode(s.replaceAll("\\s", ""))
小心。此函数不适用于超过 65000 的数据。(java 版本 1.6)
不要使用它,因为你会在jdk 9中遇到问题:java.lang.NoClassDefFoundError(javax/xml/bind/DatatypeConverter)【参考方案3】:
无需使用公共资源——Sun 提供了一个带有 Java 的 base64 编码器。你可以这样导入它:
import sun.misc.BASE64Decoder;
然后像这样使用它:
BASE64Decoder decoder = new BASE64Decoder();
byte[] decodedBytes = decoder.decodeBuffer(encodedBytes);
其中encodedBytes
是java.lang.String
或java.io.InputStream
。请注意,sun.*
类不受 Sun 的“官方支持”。
编辑:谁知道这将是我发布过的最具争议的答案?我确实知道 sun.* 软件包不受支持或保证继续存在,而且我确实了解 Commons 并一直使用它。但是,发帖人要求提供一个“包含在 Sun Java 6 中”的类,而这正是我试图回答的问题。我同意 Commons 是总体上最好的方式。
编辑 2: 正如 amir75 在下面指出的那样,Java 6+ 附带 JAXB,其中包含支持的代码来编码/解码 Base64。请参阅下面的Jeremy Ross' answer。
【讨论】:
-1 - 这是 Sun 内部代码,不是 J2SE 的一部分(它,不可移植),并且可能随时消失 - Sun 明确表示不要在用户代码中使用其内部库 是的,因此我在最后的免责声明。 这是一个短期项目,只是一个实验,不想通过审批新图书馆的过程。所以这是这个问题的正确答案。 Bzzt。在专业环境中,使用不受支持的、未记录的功能绝不是正确的决定。在企业环境中,“实验”变成了“生产代码”,没有机会修复这些漏洞。 在一个研究部门,该代码被标记为实验,当它被标记时总是被废弃,这是正确的决定。【参考方案4】:具体在Commons Codec:类Base64
到decode(byte[] array)
或encode(byte[] array)
【讨论】:
您可以将文本“Commons Codec”链接到项目页面。这样这个答案会比凯文的更好:) 我知道这是一个老问题,但为什么这不是公认的答案?大多数 java 安装中不是都包含公共编解码器,并且使用的代码行数比滚动您自己的版本少得多吗? @LiHaoyi 这个问题询问的是 Sun 的 JDK 附带的库,它不包括 Commons 中的任何内容。 假道。这些方法不存在!【参考方案5】:Guava 现在内置了 Base64 解码。
使用BaseEncoding.base64().decode()
至于处理输入使用中可能出现的空格
BaseEncoding.base64().decode(CharMatcher.WHITESPACE.removeFrom(...));
更多信息请见this discussion
【讨论】:
Guava 14 仍然是一个候选版本,但这仍然得到我的支持——当它达到任何体面的位置时,它应该是金色的 :-) Guava base64 解码器拒绝换行符和空格字符,因此您必须事先删除它们。【参考方案6】:我的解决方案是最快最简单的。
public class MyBase64
private final static char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private static int[] toInt = new int[128];
static
for(int i=0; i< ALPHABET.length; i++)
toInt[ALPHABET[i]]= i;
/**
* Translates the specified byte array into Base64 string.
*
* @param buf the byte array (not null)
* @return the translated Base64 string (not null)
*/
public static String encode(byte[] buf)
int size = buf.length;
char[] ar = new char[((size + 2) / 3) * 4];
int a = 0;
int i=0;
while(i < size)
byte b0 = buf[i++];
byte b1 = (i < size) ? buf[i++] : 0;
byte b2 = (i < size) ? buf[i++] : 0;
int mask = 0x3F;
ar[a++] = ALPHABET[(b0 >> 2) & mask];
ar[a++] = ALPHABET[((b0 << 4) | ((b1 & 0xFF) >> 4)) & mask];
ar[a++] = ALPHABET[((b1 << 2) | ((b2 & 0xFF) >> 6)) & mask];
ar[a++] = ALPHABET[b2 & mask];
switch(size % 3)
case 1: ar[--a] = '=';
case 2: ar[--a] = '=';
return new String(ar);
/**
* Translates the specified Base64 string into a byte array.
*
* @param s the Base64 string (not null)
* @return the byte array (not null)
*/
public static byte[] decode(String s)
int delta = s.endsWith( "==" ) ? 2 : s.endsWith( "=" ) ? 1 : 0;
byte[] buffer = new byte[s.length()*3/4 - delta];
int mask = 0xFF;
int index = 0;
for(int i=0; i< s.length(); i+=4)
int c0 = toInt[s.charAt( i )];
int c1 = toInt[s.charAt( i + 1)];
buffer[index++]= (byte)(((c0 << 2) | (c1 >> 4)) & mask);
if(index >= buffer.length)
return buffer;
int c2 = toInt[s.charAt( i + 2)];
buffer[index++]= (byte)(((c1 << 4) | (c2 >> 2)) & mask);
if(index >= buffer.length)
return buffer;
int c3 = toInt[s.charAt( i + 3 )];
buffer[index++]= (byte)(((c2 << 6) | c3) & mask);
return buffer;
【讨论】:
这不是越野车! - 阅读 javadoc cmets... decode(..) 的参数是 base64 字符串,而不仅仅是任何字符串。byte[] b1 = 1,2,3; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));
// => 真的
最快最简单的??重新发明***?!
我进行了一些测试,将这个类与 commons-codec 进行了比较,它似乎工作正常。我需要像这样简单的东西,因为我只需要 base64 编码并且不需要 commons-codec 提供的所有额外内容,谢谢。
这可信吗?如果您不想导入外部库,这似乎是最简单的。
它不适用于从 AES 算法获得的字节【参考方案7】:
这是我自己的实现,如果对某人有用的话:
public class Base64Coder
// The line separator string of the operating system.
private static final String systemLineSeparator = System.getProperty("line.separator");
// Mapping table from 6-bit nibbles to Base64 characters.
private static final char[] map1 = new char[64];
static
int i=0;
for (char c='A'; c<='Z'; c++) map1[i++] = c;
for (char c='a'; c<='z'; c++) map1[i++] = c;
for (char c='0'; c<='9'; c++) map1[i++] = c;
map1[i++] = '+'; map1[i++] = '/';
// Mapping table from Base64 characters to 6-bit nibbles.
private static final byte[] map2 = new byte[128];
static
for (int i=0; i<map2.length; i++) map2[i] = -1;
for (int i=0; i<64; i++) map2[map1[i]] = (byte)i;
/**
* Encodes a string into Base64 format.
* No blanks or line breaks are inserted.
* @param s A String to be encoded.
* @return A String containing the Base64 encoded data.
*/
public static String encodeString (String s)
return new String(encode(s.getBytes()));
/**
* Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters.
* This method is compatible with <code>sun.misc.BASE64Encoder.encodeBuffer(byte[])</code>.
* @param in An array containing the data bytes to be encoded.
* @return A String containing the Base64 encoded data, broken into lines.
*/
public static String encodeLines (byte[] in)
return encodeLines(in, 0, in.length, 76, systemLineSeparator);
/**
* Encodes a byte array into Base 64 format and breaks the output into lines.
* @param in An array containing the data bytes to be encoded.
* @param iOff Offset of the first byte in <code>in</code> to be processed.
* @param iLen Number of bytes to be processed in <code>in</code>, starting at <code>iOff</code>.
* @param lineLen Line length for the output data. Should be a multiple of 4.
* @param lineSeparator The line separator to be used to separate the output lines.
* @return A String containing the Base64 encoded data, broken into lines.
*/
public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator)
int blockLen = (lineLen*3) / 4;
if (blockLen <= 0) throw new IllegalArgumentException();
int lines = (iLen+blockLen-1) / blockLen;
int bufLen = ((iLen+2)/3)*4 + lines*lineSeparator.length();
StringBuilder buf = new StringBuilder(bufLen);
int ip = 0;
while (ip < iLen)
int l = Math.min(iLen-ip, blockLen);
buf.append (encode(in, iOff+ip, l));
buf.append (lineSeparator);
ip += l;
return buf.toString();
/**
* Encodes a byte array into Base64 format.
* No blanks or line breaks are inserted in the output.
* @param in An array containing the data bytes to be encoded.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode (byte[] in)
return encode(in, 0, in.length);
/**
* Encodes a byte array into Base64 format.
* No blanks or line breaks are inserted in the output.
* @param in An array containing the data bytes to be encoded.
* @param iLen Number of bytes to process in <code>in</code>.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode (byte[] in, int iLen)
return encode(in, 0, iLen);
/**
* Encodes a byte array into Base64 format.
* No blanks or line breaks are inserted in the output.
* @param in An array containing the data bytes to be encoded.
* @param iOff Offset of the first byte in <code>in</code> to be processed.
* @param iLen Number of bytes to process in <code>in</code>, starting at <code>iOff</code>.
* @return A character array containing the Base64 encoded data.
*/
public static char[] encode (byte[] in, int iOff, int iLen)
int oDataLen = (iLen*4+2)/3; // output length without padding
int oLen = ((iLen+2)/3)*4; // output length including padding
char[] out = new char[oLen];
int ip = iOff;
int iEnd = iOff + iLen;
int op = 0;
while (ip < iEnd)
int i0 = in[ip++] & 0xff;
int i1 = ip < iEnd ? in[ip++] & 0xff : 0;
int i2 = ip < iEnd ? in[ip++] & 0xff : 0;
int o0 = i0 >>> 2;
int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
int o3 = i2 & 0x3F;
out[op++] = map1[o0];
out[op++] = map1[o1];
out[op] = op < oDataLen ? map1[o2] : '='; op++;
out[op] = op < oDataLen ? map1[o3] : '='; op++;
return out;
/**
* Decodes a string from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param s A Base64 String to be decoded.
* @return A String containing the decoded data.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static String decodeString (String s)
return new String(decode(s));
/**
* Decodes a byte array from Base64 format and ignores line separators, tabs and blanks.
* CR, LF, Tab and Space characters are ignored in the input data.
* This method is compatible with <code>sun.misc.BASE64Decoder.decodeBuffer(String)</code>.
* @param s A Base64 String to be decoded.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decodeLines (String s)
char[] buf = new char[s.length()];
int p = 0;
for (int ip = 0; ip < s.length(); ip++)
char c = s.charAt(ip);
if (c != ' ' && c != '\r' && c != '\n' && c != '\t')
buf[p++] = c;
return decode(buf, 0, p);
/**
* Decodes a byte array from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param s A Base64 String to be decoded.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decode (String s)
return decode(s.toCharArray());
/**
* Decodes a byte array from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param in A character array containing the Base64 encoded data.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decode (char[] in)
return decode(in, 0, in.length);
/**
* Decodes a byte array from Base64 format.
* No blanks or line breaks are allowed within the Base64 encoded input data.
* @param in A character array containing the Base64 encoded data.
* @param iOff Offset of the first character in <code>in</code> to be processed.
* @param iLen Number of characters to process in <code>in</code>, starting at <code>iOff</code>.
* @return An array containing the decoded data bytes.
* @throws IllegalArgumentException If the input is not valid Base64 encoded data.
*/
public static byte[] decode (char[] in, int iOff, int iLen)
if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4.");
while (iLen > 0 && in[iOff+iLen-1] == '=') iLen--;
int oLen = (iLen*3) / 4;
byte[] out = new byte[oLen];
int ip = iOff;
int iEnd = iOff + iLen;
int op = 0;
while (ip < iEnd)
int i0 = in[ip++];
int i1 = in[ip++];
int i2 = ip < iEnd ? in[ip++] : 'A';
int i3 = ip < iEnd ? in[ip++] : 'A';
if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
int b0 = map2[i0];
int b1 = map2[i1];
int b2 = map2[i2];
int b3 = map2[i3];
if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
int o0 = ( b0 <<2) | (b1>>>4);
int o1 = ((b1 & 0xf)<<4) | (b2>>>2);
int o2 = ((b2 & 3)<<6) | b3;
out[op++] = (byte)o0;
if (op<oLen) out[op++] = (byte)o1;
if (op<oLen) out[op++] = (byte)o2;
return out;
// Dummy constructor.
private Base64Coder()
【讨论】:
【参考方案8】:作为sun.misc.BASE64Decoder
或非核心库的替代方案,请查看javax.mail.internet.MimeUtility.decode()
。
public static byte[] encode(byte[] b) throws Exception
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream b64os = MimeUtility.encode(baos, "base64");
b64os.write(b);
b64os.close();
return baos.toByteArray();
public static byte[] decode(byte[] b) throws Exception
ByteArrayInputStream bais = new ByteArrayInputStream(b);
InputStream b64is = MimeUtility.decode(bais, "base64");
byte[] tmp = new byte[b.length];
int n = b64is.read(tmp);
byte[] res = new byte[n];
System.arraycopy(tmp, 0, res, 0, n);
return res;
完整代码链接:Encode/Decode to/from Base64
【讨论】:
javax.mail 不是核心的一部分。 javax.mail.internet.MimeUtility 包含在 appengine-api.jar 中【参考方案9】:另一个迟到的答案,但我的基准测试显示Jetty's implementation of Base64 编码器非常快。不如MiGBase64 快,但比iHarder Base64 快。
import org.eclipse.jetty.util.B64Code;
final String decoded = B64Code.decode(encoded, "UTF-8");
我也做了一些基准测试:
library | encode | decode
------------------+--------------+-------------
'MiGBase64' | 10146001.00 | 6426446.00
'Jetty B64Code' | 8846191.00 | 3101361.75
'iHarder Base64' | 3259590.50 | 2505280.00
'Commons-Codec' | 241318.04 | 255179.96
这些是运行/秒,所以越高越好。
【讨论】:
【参考方案10】:鉴于javax.xml.bind.DatatypeConverter 使用方法parseBase64Binary() 和printBase64Binary() 参考@jeremy-ross 和@nightfirecat 答案的测试 编码/解码示例。
@Test
public void EncodeDecode()
//ENCODE
String hello = "Hello World";
byte[] helloBytes = hello.getBytes(StandardCharsets.UTF_8);
String encodedHello = DatatypeConverter.printBase64Binary(helloBytes);
LOGGER.info(hello + " encoded=> " + encodedHello);
//DECODE
byte[] encodedHelloBytes = DatatypeConverter.parseBase64Binary(encodedHello);
String helloAgain = new String(encodedHelloBytes, StandardCharsets.UTF_8) ;
LOGGER.info(encodedHello + " decoded=> " + helloAgain);
Assert.assertEquals(hello, helloAgain);
结果:
INFO - Hello World encoded=> SGVsbG8gV29ybGQ=
INFO - SGVsbG8gV29ybGQ= decoded=> Hello World
【讨论】:
【参考方案11】:使用 Java 8 -
public static String encodeString(String plainString)
return Base64.getEncoder().encodeToString(plainString.getBytes());
public static String decodeString(String encodedString)
byte[] bytes = Base64.getDecoder().decode(encodedString);
return new String(bytes);
【讨论】:
【参考方案12】:如果您更喜欢基于性能的解决方案,那么您可以使用“MiGBase64”
http://migbase64.sourceforge.net/
public class Base64Test
public static void main(String[] args)
String encodeToString = Base64.encodeToString("JavaTips.net".getBytes(), true);
System.out.println("encodeToString " + encodeToString);
byte[] decodedBytes = Base64.decode(encodeToString.getBytes());
System.out.println("decodedBytes " + new String(decodedBytes));
【讨论】:
MiGBase64 易于使用、编码良好且速度极快。很好的发现,Imby。 根据this benchmark MiGBase64 不再是最快的实现,现在它明显落后于 Apache Commons 和 sun.misc.BASE64Decoder。【参考方案13】:你可以试试这个。
byte[] data = Base64.getDecoder().decode(base64fileContent);
Base64.getDecode()
返回一个可以解码的 Base64 解码器。然后你需要使用.decode(<your base64>)
再次解码。
【讨论】:
【参考方案14】:这是一个迟到的答案,但 Joshua Bloch 在 java.util.prefs
包下提交了他的 Base64
课程(当时他为 Sun、ahem、Oracle 工作)。这个类从 JDK 1.4 开始就存在了。
例如
String currentString = "Hello World";
String base64String = java.util.prefs.Base64.byteArrayToBase64(currentString.getBytes("UTF-8"));
【讨论】:
不幸的是 Base64 类具有默认可见性,因此它几乎不是公共 API。 为什么不直接参考java.util.Base64
@LukasEder,这是因为java.util.Base64
是在 JDK 8(及更高版本)中发布的。它在早期版本中不存在。【参考方案15】:
希望对你有帮助:
import com.sun.org.apache.xml.internal.security.utils.Base64;
String str="Hello World";
String base64_str=Base64.encode(str.getBytes("UTF-8"));
或者:
String str="Hello World";
String base64_str="";
try
base64_str=(String)Class.forName("java.util.prefs.Base64").getDeclaredMethod("byteArrayToBase64", new Class[]byte[].class).invoke(null, new Object[]str.getBytes("UTF-8"));
catch (Exception ee)
java.util.prefs.Base64
在本地 rt.jar
上工作,
但它不在The JRE Class White List
而不是Available classes not listed in the GAE/J white-list
真可惜!
附言。在 android 中,这很容易,因为 android.util.Base64
自 Android API 级别 8 起已包含在内。
【讨论】:
【参考方案16】:您可以从编码的 Base64 字符串写入或下载文件:
Base64 base64 = new Base64();
String encodedFile="JVBERi0xLjUKJeLjz9MKMSAwIG9iago8PCAKICAgL1R5cGUgL0NhdGFsb2cKICAgL1BhZ2VzIDIgMCBSCiAgIC9QYWdlTGF5b3V0IC9TaW5";
byte[] dd=encodedFile.getBytes();
byte[] bytes = Base64.decodeBase64(dd);
response.setHeader("Content-disposition", "attachment; filename=\""+filename+"\"");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Expires", "-1");
// actually send result bytes
response.getOutputStream().write(bytes);
为我工作,希望也为你工作......
【讨论】:
【参考方案17】:java.util.Base64
的 Java 8 实现不依赖于其他 Java 8 特定类。
我不确定这是否适用于 Java 6 项目,但可以将 Base64.java
文件复制并粘贴到 Java 7 项目中,然后除了导入 java.util.Arrays 和 @ 之外无需修改即可编译它987654323@.
注意 Base64.java 文件被 GNU GPL2 覆盖
【讨论】:
【参考方案18】:我使用了android.util.base64
,它在没有任何依赖的情况下工作得很好:
用法:
byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT);
包 com.test;
import java.io.UnsupportedEncodingException;
/**
* Utilities for encoding and decoding the Base64 representation of
* binary data. See RFCs <a
* href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a
* href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>.
*/
public class Base64
public static final int DEFAULT = 0;
public static final int NO_PADDING = 1;
public static final int NO_WRAP = 2;
public static final int CRLF = 4;
public static final int URL_SAFE = 8;
public static final int NO_CLOSE = 16;
// --------------------------------------------------------
// shared code
// --------------------------------------------------------
/* package */ static abstract class Coder
public byte[] output;
public int op;
public abstract boolean process(byte[] input, int offset, int len, boolean finish);
public abstract int maxOutputSize(int len);
// --------------------------------------------------------
// decoding
// --------------------------------------------------------
public static byte[] decode(String str, int flags)
return decode(str.getBytes(), flags);
public static byte[] decode(byte[] input, int flags)
return decode(input, 0, input.length, flags);
public static byte[] decode(byte[] input, int offset, int len, int flags)
// Allocate space for the most data the input could represent.
// (It could contain less if it contains whitespace, etc.)
Decoder decoder = new Decoder(flags, new byte[len*3/4]);
if (!decoder.process(input, offset, len, true))
throw new IllegalArgumentException("bad base-64");
// Maybe we got lucky and allocated exactly enough output space.
if (decoder.op == decoder.output.length)
return decoder.output;
// Need to shorten the array, so allocate a new one of the
// right size and copy.
byte[] temp = new byte[decoder.op];
System.arraycopy(decoder.output, 0, temp, 0, decoder.op);
return temp;
static class Decoder extends Coder
private static final int DECODE[] =
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
;
/**
* Decode lookup table for the "web safe" variant (RFC 3548
* sec. 4) where - and _ replace + and /.
*/
private static final int DECODE_WEBSAFE[] =
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
;
/** Non-data values in the DECODE arrays. */
private static final int SKIP = -1;
private static final int EQUALS = -2;
private int state; // state number (0 to 6)
private int value;
final private int[] alphabet;
public Decoder(int flags, byte[] output)
this.output = output;
alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
state = 0;
value = 0;
public int maxOutputSize(int len)
return len * 3/4 + 10;
/**
* Decode another block of input data.
*
* @return true if the state machine is still healthy. false if
* bad base-64 data has been detected in the input stream.
*/
public boolean process(byte[] input, int offset, int len, boolean finish)
if (this.state == 6) return false;
int p = offset;
len += offset;
int state = this.state;
int value = this.value;
int op = 0;
final byte[] output = this.output;
final int[] alphabet = this.alphabet;
while (p < len)
if (state == 0)
while (p+4 <= len &&
(value = ((alphabet[input[p] & 0xff] << 18) |
(alphabet[input[p+1] & 0xff] << 12) |
(alphabet[input[p+2] & 0xff] << 6) |
(alphabet[input[p+3] & 0xff]))) >= 0)
output[op+2] = (byte) value;
output[op+1] = (byte) (value >> 8);
output[op] = (byte) (value >> 16);
op += 3;
p += 4;
if (p >= len) break;
int d = alphabet[input[p++] & 0xff];
switch (state)
case 0:
if (d >= 0)
value = d;
++state;
else if (d != SKIP)
this.state = 6;
return false;
break;
case 1:
if (d >= 0)
value = (value << 6) | d;
++state;
else if (d != SKIP)
this.state = 6;
return false;
break;
case 2:
if (d >= 0)
value = (value << 6) | d;
++state;
else if (d == EQUALS)
// Emit the last (partial) output tuple;
// expect exactly one more padding character.
output[op++] = (byte) (value >> 4);
state = 4;
else if (d != SKIP)
this.state = 6;
return false;
break;
case 3:
if (d >= 0)
// Emit the output triple and return to state 0.
value = (value << 6) | d;
output[op+2] = (byte) value;
output[op+1] = (byte) (value >> 8);
output[op] = (byte) (value >> 16);
op += 3;
state = 0;
else if (d == EQUALS)
// Emit the last (partial) output tuple;
// expect no further data or padding characters.
output[op+1] = (byte) (value >> 2);
output[op] = (byte) (value >> 10);
op += 2;
state = 5;
else if (d != SKIP)
this.state = 6;
return false;
break;
case 4:
if (d == EQUALS)
++state;
else if (d != SKIP)
this.state = 6;
return false;
break;
case 5:
if (d != SKIP)
this.state = 6;
return false;
break;
if (!finish)
// We're out of input, but a future call could provide
// more.
this.state = state;
this.value = value;
this.op = op;
return true;
switch (state)
case 0:
break;
case 1:
this.state = 6;
return false;
case 2:
output[op++] = (byte) (value >> 4);
break;
case 3:
output[op++] = (byte) (value >> 10);
output[op++] = (byte) (value >> 2);
break;
case 4:
this.state = 6;
return false;
case 5:
break;
this.state = state;
this.op = op;
return true;
// --------------------------------------------------------
// encoding
// --------------------------------------------------------
public static String encodeToString(byte[] input, int flags)
try
return new String(encode(input, flags), "US-ASCII");
catch (UnsupportedEncodingException e)
// US-ASCII is guaranteed to be available.
throw new AssertionError(e);
public static String encodeToString(byte[] input, int offset, int len, int flags)
try
return new String(encode(input, offset, len, flags), "US-ASCII");
catch (UnsupportedEncodingException e)
// US-ASCII is guaranteed to be available.
throw new AssertionError(e);
public static byte[] encode(byte[] input, int flags)
return encode(input, 0, input.length, flags);
public static byte[] encode(byte[] input, int offset, int len, int flags)
Encoder encoder = new Encoder(flags, null);
// Compute the exact length of the array we will produce.
int output_len = len / 3 * 4;
// Account for the tail of the data and the padding bytes, if any.
if (encoder.do_padding)
if (len % 3 > 0)
output_len += 4;
else
switch (len % 3)
case 0: break;
case 1: output_len += 2; break;
case 2: output_len += 3; break;
// Account for the newlines, if any.
if (encoder.do_newline && len > 0)
output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) *
(encoder.do_cr ? 2 : 1);
encoder.output = new byte[output_len];
encoder.process(input, offset, len, true);
assert encoder.op == output_len;
return encoder.output;
/* package */ static class Encoder extends Coder
/**
* Emit a new line every this many output tuples. Corresponds to
* a 76-character line length (the maximum allowable according to
* <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>).
*/
public static final int LINE_GROUPS = 19;
/**
* Lookup table for turning Base64 alphabet positions (6 bits)
* into output bytes.
*/
private static final byte ENCODE[] =
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
;
/**
* Lookup table for turning Base64 alphabet positions (6 bits)
* into output bytes.
*/
private static final byte ENCODE_WEBSAFE[] =
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
;
final private byte[] tail;
/* package */ int tailLen;
private int count;
final public boolean do_padding;
final public boolean do_newline;
final public boolean do_cr;
final private byte[] alphabet;
public Encoder(int flags, byte[] output)
this.output = output;
do_padding = (flags & NO_PADDING) == 0;
do_newline = (flags & NO_WRAP) == 0;
do_cr = (flags & CRLF) != 0;
alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
tail = new byte[2];
tailLen = 0;
count = do_newline ? LINE_GROUPS : -1;
/**
* @return an overestimate for the number of bytes @code
* len bytes could encode to.
*/
public int maxOutputSize(int len)
return len * 8/5 + 10;
public boolean process(byte[] input, int offset, int len, boolean finish)
// Using local variables makes the encoder about 9% faster.
final byte[] alphabet = this.alphabet;
final byte[] output = this.output;
int op = 0;
int count = this.count;
int p = offset;
len += offset;
int v = -1;
// First we need to concatenate the tail of the previous call
// with any input bytes available now and see if we can empty
// the tail.
switch (tailLen)
case 0:
// There was no tail.
break;
case 1:
if (p+2 <= len)
// A 1-byte tail with at least 2 bytes of
// input available now.
v = ((tail[0] & 0xff) << 16) |
((input[p++] & 0xff) << 8) |
(input[p++] & 0xff);
tailLen = 0;
;
break;
case 2:
if (p+1 <= len)
// A 2-byte tail with at least 1 byte of input.
v = ((tail[0] & 0xff) << 16) |
((tail[1] & 0xff) << 8) |
(input[p++] & 0xff);
tailLen = 0;
break;
if (v != -1)
output[op++] = alphabet[(v >> 18) & 0x3f];
output[op++] = alphabet[(v >> 12) & 0x3f];
output[op++] = alphabet[(v >> 6) & 0x3f];
output[op++] = alphabet[v & 0x3f];
if (--count == 0)
if (do_cr) output[op++] = '\r';
output[op++] = '\n';
count = LINE_GROUPS;
// At this point either there is no tail, or there are fewer
// than 3 bytes of input available.
// The main loop, turning 3 input bytes into 4 output bytes on
// each iteration.
while (p+3 <= len)
v = ((input[p] & 0xff) << 16) |
((input[p+1] & 0xff) << 8) |
(input[p+2] & 0xff);
output[op] = alphabet[(v >> 18) & 0x3f];
output[op+1] = alphabet[(v >> 12) & 0x3f];
output[op+2] = alphabet[(v >> 6) & 0x3f];
output[op+3] = alphabet[v & 0x3f];
p += 3;
op += 4;
if (--count == 0)
if (do_cr) output[op++] = '\r';
output[op++] = '\n';
count = LINE_GROUPS;
if (finish)
if (p-tailLen == len-1)
int t = 0;
v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4;
tailLen -= t;
output[op++] = alphabet[(v >> 6) & 0x3f];
output[op++] = alphabet[v & 0x3f];
if (do_padding)
output[op++] = '=';
output[op++] = '=';
if (do_newline)
if (do_cr) output[op++] = '\r';
output[op++] = '\n';
else if (p-tailLen == len-2)
int t = 0;
v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) |
(((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2);
tailLen -= t;
output[op++] = alphabet[(v >> 12) & 0x3f];
output[op++] = alphabet[(v >> 6) & 0x3f];
output[op++] = alphabet[v & 0x3f];
if (do_padding)
output[op++] = '=';
if (do_newline)
if (do_cr) output[op++] = '\r';
output[op++] = '\n';
else if (do_newline && op > 0 && count != LINE_GROUPS)
if (do_cr) output[op++] = '\r';
output[op++] = '\n';
assert tailLen == 0;
assert p == len;
else
// Save the leftovers in tail to be consumed on the next
// call to encodeInternal.
if (p == len-1)
tail[tailLen++] = input[p];
else if (p == len-2)
tail[tailLen++] = input[p];
tail[tailLen++] = input[p+1];
this.op = op;
this.count = count;
return true;
private Base64() // don't instantiate
【讨论】:
【参考方案19】:在使用 Java 7 编译但可能在更高 Java 版本中运行的代码中,检测 java.util.Base64
类的存在并使用最适合此处其他问题中提到的给定 JVM 的方法似乎很有用。
我使用了这个代码:
private static final Method JAVA_UTIL_BASE64_GETENCODER;
static
Method getEncoderMethod;
try
final Class<?> base64Class = Class.forName("java.util.Base64");
getEncoderMethod = base64Class.getMethod("getEncoder");
catch (ClassNotFoundException | NoSuchMethodException e)
getEncoderMethod = null;
JAVA_UTIL_BASE64_GETENCODER = getEncoderMethod;
static String base64EncodeToString(String s)
final byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
if (JAVA_UTIL_BASE64_GETENCODER == null)
// Java 7 and older // TODO: remove this branch after switching to Java 8
return DatatypeConverter.printBase64Binary(bytes);
else
// Java 8 and newer
try
final Object encoder = JAVA_UTIL_BASE64_GETENCODER.invoke(null);
final Class<?> encoderClass = encoder.getClass();
final Method encodeMethod = encoderClass.getMethod("encode", byte[].class);
final byte[] encodedBytes = (byte[]) encodeMethod.invoke(encoder, bytes);
return new String(encodedBytes);
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e)
throw new IllegalStateException(e);
【讨论】:
【参考方案20】:import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
/***
*
* @author Vaquar khan
*
*
*/
public class AES
private static SecretKeySpec secretKey;
private static final String VK_secretKey = "VaquarKhan-secrate-key!!!!";
private static byte[] key;
/**
*
* @param myKey
*/
public static void setKey(String myKey)
MessageDigest sha = null;
try
key = myKey.getBytes("UTF-8");
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
catch (NoSuchAlgorithmException e)
e.printStackTrace();
catch (UnsupportedEncodingException e)
e.printStackTrace();
/**
* encrypt
* @param strToEncrypt
* @param secret
* @return
*/
public static String encrypt(String strToEncrypt, String secret)
try
setKey(secret);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
catch (Exception e)
System.out.println("Error while encrypting: " + e.toString());
return null;
/**
* decrypt
* @param strToDecrypt
* @param secret
* @return
*/
public static String decrypt(String strToDecrypt, String secret)
try
setKey(secret);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
catch (Exception e)
System.out.println("Error while decrypting: " + e.toString());
return null;
public static void main(String[] args)
final String secretKey = VK_secretKey;
String password = "VKhan@12";
//
String encryptedString = AES.encrypt(password, secretKey);
String decryptedString = AES.decrypt(encryptedString, secretKey);
//
System.out.println(password);
System.out.println(encryptedString);
System.out.println(decryptedString);
【讨论】:
以上是关于在 Java 中解码 Base64 数据的主要内容,如果未能解决你的问题,请参考以下文章