Tengo una imagen codificada en Base64. ¿Cuál es la mejor manera de decodificar eso en Java? Esperemos que solo use las bibliotecas incluidas con Sun Java 6.
No importa qué tipo de aplicación esté usando (experimente o no), es tan simple como crear un solo archivo Base64.java en su paquete de utilidades usando el código aquí: migbase64.sourceforge.net Mire los gráficos de rendimiento y note la diferencia: 4-5 veces más rápido.
javacoder
FYI: JEP 135 propone introducir una API estándar y reconocible para esto en la plataforma Java.
Sin embargo, parece que el printBase64Binary(..)método no hace la versión MIME de Base64 ( en.wikipedia.org/wiki/Base64#MIME ), mientras que las implementaciones privadas de Sun y Commons lo usan. Específicamente, para cadenas de más de 76 caracteres, se agregan nuevas líneas. No encontré cómo configurar la implementación de JAXB para este comportamiento ... :-(
KLE
77
sin embargo, la implementación del sol ignorará las nuevas líneas. Entonces son compatibles.
Esben Skov Pedersen
99
¡Advertencia! parseBase64Binary omitirá silenciosamente caracteres no válidos y no verificará la validez de base64. Es mejor usar Commons Codec o Guava Base64. Tenga en cuenta que Guava rechaza las líneas nuevas y los caracteres de espacios en blanco, por lo que debe analizar cadenas con espacios en blanco omitidos: BaseEncoding.base64 (). Decode (s.replaceAll ("\\ s", ""))
Martin Vysny
99
Ten cuidado. Esta función no funciona con datos superiores a 65000. (Java versión 1.6)
Hüseyin Yağlı
55
No lo use, porque obtendrá problemas en jdk 9: java.lang.NoClassDefFoundError (javax / xml / bind / DatatypeConverter)
rupashka
381
A partir de Java 8 , existe una API oficialmente compatible para la codificación y decodificación Base64. Con el tiempo, esto probablemente se convertirá en la opción predeterminada.
La API incluye la clase java.util.Base64y sus clases anidadas. Admite tres tipos diferentes: básico, seguro para URL y MIME.
Código de muestra usando la codificación "básica":
La documentaciónjava.util.Base64 incluye varios métodos más para configurar codificadores y decodificadores, y para usar diferentes clases como entradas y salidas (conjuntos de bytes, cadenas, ByteBuffers, flujos java.io).
Estoy usando Java 8. ¿Es este el enfoque recomendado si uso Java 8?
JohnMerlino
44
@JohnMerlino si no se requiere compatibilidad con versiones anteriores de Java, recomendaría usar esta API ya que JRE tiene una política de compatibilidad más sólida que la mayoría de las bibliotecas. Además, al estar incluido en el JRE, no limita sus dependencias de ninguna manera posible.
Andrea
44
Java 7 está EOLed, Java 9 está llegando, ¡esta es la respuesta correcta para mí!
eskatos
1
Casi bueno: esto solo acepta flujos base64 sin procesar, no archivos base64. Tuve que usar final byte[] decoded = Base64.getMimeDecoder().decode(encoded);en su lugar. ¡Pero gracias de cualquier manera! (Agradable con commons-io FileUtils.readFileToByteArrayy FileUtils.writeByteArrayToFile, especialmente cuando te das cuenta de que también encodedpuede ser un byte[].)
mirabilos
101
No es necesario usar commons: Sun envía un codificador base64 con Java. Puedes importarlo como tal:
¿Dónde encodedBytesestá a java.lang.Stringo a java.io.InputStream. Solo tenga en cuenta que las sun.*clases no son "oficialmente compatibles" con Sun.
EDITAR: ¿Quién sabía que esta sería la respuesta más controvertida que publicaría? Sé que los paquetes sun. * No son compatibles ni se garantiza que continúen existiendo, y sí sé sobre Commons y lo uso todo el tiempo. Sin embargo, el póster solicitó una clase que estaba "incluida con Sun Java 6", y eso es lo que estaba tratando de responder. Estoy de acuerdo en que Commons es la mejor manera de ir en general.
EDIT 2: Como señala amir75 a continuación, Java 6+ se envía con JAXB, que contiene código compatible para codificar / decodificar Base64. Vea la respuesta de Jeremy Ross a continuación.
-1 - este es el código interno de Sun, NO es parte de J2SE (no es portátil) y puede desaparecer en cualquier momento - Sun dice explícitamente que NO use sus bibliotecas internas en el código de usuario
kdgregory
59
Es cierto, de ahí mi descargo de responsabilidad al final.
MattK
20
Esto es para un proyecto a corto plazo y es solo un experimento y no quiero pasar por el proceso de aprobación de una nueva biblioteca. Entonces esta es la respuesta correcta a esta pregunta.
Ryan P
44
Bzzt. En un entorno profesional, el uso de una función no respaldada y no documentada nunca es la decisión correcta. Y en un entorno corporativo, los "experimentos" se convierten en "código de producción" sin posibilidad de arreglar los hacks.
kdgregory
29
En un departamento de investigación donde ese código se marca como experimento y cuando se marca siempre se descarta, es la decisión correcta.
Ryan P
55
Específicamente en Commons Codec : clase Base64a decode(byte[] array)oencode(byte[] array)
Puede vincular el texto 'Commons Codec' a la página del proyecto. De esa manera, esta respuesta sería mejor que la de Kevin :)
mmutilva
1
Sé que esta es una vieja pregunta, pero ¿por qué no es esta la respuesta aceptada? ¿No se incluye el códec commons con la mayoría de las instalaciones de Java, y muchas menos líneas de código para usar que la creación de su propia versión?
Li Haoyi
2
@LiHaoyi La pregunta solicitó bibliotecas que se enviaron con Sun's JDK, que no incluye nada de los Comunes.
Ti Strga
1
Falsa pista. ¡Estos métodos no existen!
Nicolas Barbulesco
36
La guayaba ahora tiene decodificación Base64 incorporada.
Guava 14 sigue siendo un candidato para la liberación, pero todavía recibe mi voto positivo: para cuando llegue a una posición decente, debería ser dorado :-)
Peter Becker
1
El decodificador base64 de Guava rechaza los caracteres de nueva línea y espacio, por lo que debe eliminarlos de antemano.
Martin Vysny
34
Mi solución es más rápida y fácil.
publicclassMyBase64{privatefinalstaticchar[] ALPHABET ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();privatestaticint[] toInt =newint[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)
*/publicstaticString encode(byte[] buf){int size = buf.length;char[] ar =newchar[((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){case1: ar[--a]='=';case2: ar[--a]='=';}returnnewString(ar);}/**
* Translates the specified Base64 string into a byte array.
*
* @param s the Base64 string (not null)
* @return the byte array (not null)
*/publicstaticbyte[] decode(String s){int delta = s.endsWith("==")?2: s.endsWith("=")?1:0;byte[] buffer =newbyte[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;}}
no es buggy! - lea los comentarios de javadoc ... el parámetro de decodificación (..) es una cadena base64 , no cualquier cadena. byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));// => verdadero
GeorgeK
99
¿Más rápido y más fácil? Reinventando la rueda ?!
Nicolas Barbulesco
77
Ejecuté algunas pruebas comparando esta clase con el códec commons y parece funcionar bien. Necesitaba algo simple como esto porque solo necesitaba la codificación base64 y no quería todas las cosas adicionales que proporciona el códec commons, gracias.
Michael
2
¿Es esto confiable? Parece ser la más fácil si no desea importar bibliotecas externas.
Felipe
2
no funciona con bytes obtenidos del algoritmo AES
shontauro
11
Aquí está mi propia implementación, si podría ser útil para alguien:
publicclassBase64Coder{// The line separator string of the operating system.privatestaticfinalString systemLineSeparator =System.getProperty("line.separator");// Mapping table from 6-bit nibbles to Base64 characters.privatestaticfinalchar[] map1 =newchar[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.privatestaticfinalbyte[] map2 =newbyte[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.
*/publicstaticString encodeString (String s){returnnewString(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.
*/publicstaticString 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.
*/publicstaticString encodeLines (byte[] in,int iOff,int iLen,int lineLen,String lineSeparator){int blockLen =(lineLen*3)/4;if(blockLen <=0)thrownewIllegalArgumentException();int lines =(iLen+blockLen-1)/ blockLen;int bufLen =((iLen+2)/3)*4+ lines*lineSeparator.length();StringBuilder buf =newStringBuilder(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.
*/publicstaticchar[] 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.
*/publicstaticchar[] 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.
*/publicstaticchar[] encode (byte[] in,int iOff,int iLen){int oDataLen =(iLen*4+2)/3;// output length without paddingint oLen =((iLen+2)/3)*4;// output length including paddingchar[] out =newchar[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.
*/publicstaticString decodeString (String s){returnnewString(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.
*/publicstaticbyte[] decodeLines (String s){char[] buf =newchar[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.
*/publicstaticbyte[] 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.
*/publicstaticbyte[] 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.
*/publicstaticbyte[] decode (char[] in,int iOff,int iLen){if(iLen%4!=0)thrownewIllegalArgumentException("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 =newbyte[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)thrownewIllegalArgumentException("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)thrownewIllegalArgumentException("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.privateBase64Coder(){}}
MiGBase64 es fácil de usar, está bien codificado y es increíblemente rápido. Buen hallazgo, Imby.
mukama
Según este punto de referencia, MiGBase64 ya no es la implementación más rápida, y ahora está muy por detrás de Apache Commons y sun.misc.BASE64Decoder de manera significativa.
Andrea
3
Esta es una respuesta tardía , pero Joshua Bloch comprometió su Base64clase (cuando trabajaba para Sun, ejem, Oracle) bajo el java.util.prefspaquete. Esta clase existió desde JDK 1.4.
La implementación de Java 8 java.util.Base64no tiene dependencias en otras clases específicas de Java 8.
No estoy seguro de si esto funcionará para el proyecto Java 6, pero es posible copiar y pegar el Base64.javaarchivo en un proyecto Java 7 y compilarlo sin otra modificación que la importación de java.util.Arrays y java.util.Objects.
Tenga en cuenta que el archivo Base64.java está cubierto por GNU GPL2
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>.
*/publicclassBase64{publicstaticfinalint DEFAULT =0;publicstaticfinalint NO_PADDING =1;publicstaticfinalint NO_WRAP =2;publicstaticfinalint CRLF =4;publicstaticfinalint URL_SAFE =8;publicstaticfinalint NO_CLOSE =16;// --------------------------------------------------------// shared code// --------------------------------------------------------/* package */staticabstractclassCoder{publicbyte[] output;publicint op;publicabstractboolean process(byte[] input,int offset,int len,boolean finish);publicabstractint maxOutputSize(int len);}// --------------------------------------------------------// decoding// --------------------------------------------------------publicstaticbyte[] decode(String str,int flags){return decode(str.getBytes(), flags);}publicstaticbyte[] decode(byte[] input,int flags){return decode(input,0, input.length, flags);}publicstaticbyte[] 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 =newDecoder(flags,newbyte[len*3/4]);if(!decoder.process(input, offset, len,true)){thrownewIllegalArgumentException("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 =newbyte[decoder.op];System.arraycopy(decoder.output,0, temp,0, decoder.op);return temp;}staticclassDecoderextendsCoder{privatestaticfinalint 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 /.
*/privatestaticfinalint 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. */privatestaticfinalint SKIP =-1;privatestaticfinalint EQUALS =-2;privateint state;// state number (0 to 6)privateint value;finalprivateint[] alphabet;publicDecoder(int flags,byte[] output){this.output = output;
alphabet =((flags & URL_SAFE)==0)? DECODE : DECODE_WEBSAFE;
state =0;
value =0;}publicint 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.
*/publicboolean process(byte[] input,int offset,int len,boolean finish){if(this.state ==6)returnfalse;int p = offset;
len += offset;int state =this.state;int value =this.value;int op =0;finalbyte[] output =this.output;finalint[] 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){case0:if(d >=0){
value = d;++state;}elseif(d != SKIP){this.state =6;returnfalse;}break;case1:if(d >=0){
value =(value <<6)| d;++state;}elseif(d != SKIP){this.state =6;returnfalse;}break;case2:if(d >=0){
value =(value <<6)| d;++state;}elseif(d == EQUALS){// Emit the last (partial) output tuple;// expect exactly one more padding character.
output[op++]=(byte)(value >>4);
state =4;}elseif(d != SKIP){this.state =6;returnfalse;}break;case3: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;}elseif(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;}elseif(d != SKIP){this.state =6;returnfalse;}break;case4:if(d == EQUALS){++state;}elseif(d != SKIP){this.state =6;returnfalse;}break;case5:if(d != SKIP){this.state =6;returnfalse;}break;}}if(!finish){// We're out of input, but a future call could provide// more.this.state = state;this.value = value;this.op = op;returntrue;}switch(state){case0:break;case1:this.state =6;returnfalse;case2:
output[op++]=(byte)(value >>4);break;case3:
output[op++]=(byte)(value >>10);
output[op++]=(byte)(value >>2);break;case4:this.state =6;returnfalse;case5:break;}this.state = state;this.op = op;returntrue;}}// --------------------------------------------------------// encoding// -------------------------------------------------------- publicstaticString encodeToString(byte[] input,int flags){try{returnnewString(encode(input, flags),"US-ASCII");}catch(UnsupportedEncodingException e){// US-ASCII is guaranteed to be available.thrownewAssertionError(e);}}publicstaticString encodeToString(byte[] input,int offset,int len,int flags){try{returnnewString(encode(input, offset, len, flags),"US-ASCII");}catch(UnsupportedEncodingException e){// US-ASCII is guaranteed to be available.thrownewAssertionError(e);}}publicstaticbyte[] encode(byte[] input,int flags){return encode(input,0, input.length, flags);}publicstaticbyte[] encode(byte[] input,int offset,int len,int flags){Encoder encoder =newEncoder(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){case0:break;case1: output_len +=2;break;case2: 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 =newbyte[output_len];
encoder.process(input, offset, len,true);assert encoder.op == output_len;return encoder.output;}/* package */staticclassEncoderextendsCoder{/**
* 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>).
*/publicstaticfinalint LINE_GROUPS =19;/**
* Lookup table for turning Base64 alphabet positions (6 bits)
* into output bytes.
*/privatestaticfinalbyte 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.
*/privatestaticfinalbyte 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','-','_',};finalprivatebyte[] tail;/* package */int tailLen;privateint count;finalpublicboolean do_padding;finalpublicboolean do_newline;finalpublicboolean do_cr;finalprivatebyte[] alphabet;publicEncoder(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 =newbyte[2];
tailLen =0;
count = do_newline ? LINE_GROUPS :-1;}/**
* @return an overestimate for the number of bytes {@code
* len} bytes could encode to.
*/publicint maxOutputSize(int len){return len *8/5+10;}publicboolean process(byte[] input,int offset,int len,boolean finish){// Using local variables makes the encoder about 9% faster.finalbyte[] alphabet =this.alphabet;finalbyte[] 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){case0:// There was no tail.break;case1: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;case2: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';}}elseif(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';}}elseif(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];}elseif(p == len-2){
tail[tailLen++]= input[p];
tail[tailLen++]= input[p+1];}}this.op = op;this.count = count;returntrue;}}privateBase64(){}// don't instantiate}
En un código compilado con Java 7 pero que potencialmente se ejecuta en una versión superior de Java, parece útil detectar la presencia de la java.util.Base64clase y utilizar el mejor enfoque para la JVM dada mencionada en otras preguntas aquí.
Respuestas:
A partir de la v6, Java SE se entrega con JAXB.
javax.xml.bind.DatatypeConverter
tiene métodos estáticos que lo hacen fácil. VerparseBase64Binary()
yprintBase64Binary()
.fuente
printBase64Binary(..)
método no hace la versión MIME de Base64 ( en.wikipedia.org/wiki/Base64#MIME ), mientras que las implementaciones privadas de Sun y Commons lo usan. Específicamente, para cadenas de más de 76 caracteres, se agregan nuevas líneas. No encontré cómo configurar la implementación de JAXB para este comportamiento ... :-(A partir de Java 8 , existe una API oficialmente compatible para la codificación y decodificación Base64. Con el tiempo, esto probablemente se convertirá en la opción predeterminada.
La API incluye la clase
java.util.Base64
y sus clases anidadas. Admite tres tipos diferentes: básico, seguro para URL y MIME.Código de muestra usando la codificación "básica":
La documentación
java.util.Base64
incluye varios métodos más para configurar codificadores y decodificadores, y para usar diferentes clases como entradas y salidas (conjuntos de bytes, cadenas, ByteBuffers, flujos java.io).fuente
final byte[] decoded = Base64.getMimeDecoder().decode(encoded);
en su lugar. ¡Pero gracias de cualquier manera! (Agradable con commons-ioFileUtils.readFileToByteArray
yFileUtils.writeByteArrayToFile
, especialmente cuando te das cuenta de que tambiénencoded
puede ser unbyte[]
.)No es necesario usar commons: Sun envía un codificador base64 con Java. Puedes importarlo como tal:
Y luego úsalo así:
¿Dónde
encodedBytes
está ajava.lang.String
o ajava.io.InputStream
. Solo tenga en cuenta que lassun.*
clases no son "oficialmente compatibles" con Sun.EDITAR: ¿Quién sabía que esta sería la respuesta más controvertida que publicaría? Sé que los paquetes sun. * No son compatibles ni se garantiza que continúen existiendo, y sí sé sobre Commons y lo uso todo el tiempo. Sin embargo, el póster solicitó una clase que estaba "incluida con Sun Java 6", y eso es lo que estaba tratando de responder. Estoy de acuerdo en que Commons es la mejor manera de ir en general.
EDIT 2: Como señala amir75 a continuación, Java 6+ se envía con JAXB, que contiene código compatible para codificar / decodificar Base64. Vea la respuesta de Jeremy Ross a continuación.
fuente
Específicamente en Commons Codec : clase
Base64
adecode(byte[] array)
oencode(byte[] array)
fuente
La guayaba ahora tiene decodificación Base64 incorporada.
Utilice BaseEncoding.base64 (). Decode ()
En cuanto a tratar con posibles espacios en blanco en el uso de entrada
BaseEncoding.base64().decode(CharMatcher.WHITESPACE.removeFrom(...));
Vea esta discusión para más información
fuente
Mi solución es más rápida y fácil.
fuente
byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));
// => verdaderoAquí está mi propia implementación, si podría ser útil para alguien:
fuente
Como una alternativa a
sun.misc.BASE64Decoder
las bibliotecas o no centrales, mirajavax.mail.internet.MimeUtility.decode()
.Enlace con código completo: codificar / decodificar a / desde Base64
fuente
Otra respuesta tardía, pero mi evaluación comparativa muestra que la implementación de Jetty del codificador Base64 es bastante rápida. No tan rápido como MiGBase64 pero más rápido que iHarder Base64 .
También hice algunos puntos de referencia:
Estas son carreras / segundo, por lo que cuanto más alto, mejor.
fuente
Dado un ejemplo de prueba de codificación / decodificación de javax.xml.bind.DatatypeConverter usando los métodos parseBase64Binary () e printBase64Binary () en referencia a @ jeremy-ross y @nightfirecat answer.
Resultado:
fuente
Si prefiere una solución basada en el rendimiento, puede usar "MiGBase64"
http://migbase64.sourceforge.net/
fuente
Esta es una respuesta tardía , pero Joshua Bloch comprometió su
Base64
clase (cuando trabajaba para Sun, ejem, Oracle) bajo eljava.util.prefs
paquete. Esta clase existió desde JDK 1.4.P.ej
fuente
java.util.Base64
java.util.Base64
fue lanzado en JDK 8 (y superior). No existe en versiones anteriores.Espero que esto te ayude:
O:
java.util.prefs.Base64
trabaja en localrt.jar
,Pero no está en la Lista Blanca de la Clase JRE
y no en Clases disponibles que no figuran en la lista blanca de GAE / J
¡Qué pena!
PD. En Android, es fácil porque
android.util.Base64
se ha incluido desde el nivel 8 de la API de Android.fuente
Puede escribir o descargar un archivo de la cadena Base64 codificada:
Trabajó para mí y espero que también para ti ...
fuente
La implementación de Java 8
java.util.Base64
no tiene dependencias en otras clases específicas de Java 8.No estoy seguro de si esto funcionará para el proyecto Java 6, pero es posible copiar y pegar el
Base64.java
archivo en un proyecto Java 7 y compilarlo sin otra modificación que la importación de java.util.Arrays yjava.util.Objects
.Tenga en cuenta que el archivo Base64.java está cubierto por GNU GPL2
fuente
Usé
android.util.base64
que funciona bastante bien sin ninguna dependencia:Uso:
paquete com.test;
fuente
Usando Java 8 -
fuente
Simplemente puedes probar esto.
"Base64.getDecode ()" devuelve un decodificador Base64 que puede decodificarse. Entonces necesitas decodificarlo nuevamente usando ".decode ()"
fuente
En un código compilado con Java 7 pero que potencialmente se ejecuta en una versión superior de Java, parece útil detectar la presencia de la
java.util.Base64
clase y utilizar el mejor enfoque para la JVM dada mencionada en otras preguntas aquí.Usé este código:
fuente
fuente