Eu tenho uma imagem que é codificada em Base64. Qual é a melhor maneira de decodificar isso em Java? Esperançosamente, usando apenas as bibliotecas incluídas no Sun Java 6.
Não importa que tipo de aplicativo você esteja usando (experimente ou não), é tão simples quanto criar um único arquivo Base64.java no pacote utils usando o código aqui: migbase64.sourceforge.net Veja os gráficos de desempenho e observe a diferença: 4-5 vezes mais rápido.
Javacoder 26/03
FYI: O JEP 135 propõe a introdução de uma API padrão e detectável na plataforma Java.
No entanto, parece que o printBase64Binary(..)método não executa a versão MIME do Base64 ( en.wikipedia.org/wiki/Base64#MIME ), enquanto as implementações particulares da Sun e do Commons usam isso. Especificamente, para String com mais de 76 caracteres, novas linhas são adicionadas. Eu não encontrei como configurar a implementação do JAXB para esse comportamento ... :-(
KLE
7
no entanto, a implementação do sol ignorará novas linhas. Então eles são compatíveis.
Esben Skov Pedersen
9
Atenção! parseBase64Binary ignorará silenciosamente caracteres inválidos e não verificará a validade da base64. É melhor usar o Commons Codec ou o Guava Base64. Note-se que Goiaba rejeita novas linhas e espaços em branco caracteres, então você precisa para cordas de análise com espaços em branco omitido:. BaseEncoding.base64 () decodificação (s.replaceAll ( "\\ s", ""))
Martin Vysny
9
Seja cuidadoso. Esta função não funciona com dados maiores que 65000. (versão java 1.6)
Hüseyin Yağlı
5
Não usá-lo, porque você vai ter problemas no jdk 9: java.lang.NoClassDefFoundError (javax / xml / bind / DatatypeConverter)
rupashka
381
A partir do Java 8 , há uma API oficialmente suportada para codificação e decodificação Base64. Com o tempo, isso provavelmente se tornará a opção padrão.
A API inclui a classe java.util.Base64e suas classes aninhadas. Ele suporta três tipos diferentes: básico, seguro de URL e MIME.
A documentação parajava.util.Base64 inclui vários outros métodos para configurar codificadores e decodificadores e para usar diferentes classes como entradas e saídas (matrizes de bytes, seqüências de caracteres, ByteBuffers, fluxos java.io).
Estou usando o Java 8. Essa é a abordagem recomendada se você estiver usando o Java 8?
JohnMerlino
4
@JohnMerlino se a compatibilidade com versões mais antigas de Java não for necessária, eu recomendaria o uso desta API, pois o JRE possui uma política de compatibilidade mais forte do que a maioria das bibliotecas. Além disso, ao ser incluído no JRE, ele não restringe suas dependências de nenhuma maneira possível.
Andrea
4
Java 7 é EOLed, Java 9 está chegando, esta é a resposta certa para mim!
Eskatos
1
Quase bom: isso aceita apenas fluxos base64 brutos, não arquivos base64. Eu tive que usar em seu final byte[] decoded = Base64.getMimeDecoder().decode(encoded);lugar. Mas obrigada mesmo assim! (Nice com commons-io FileUtils.readFileToByteArraye FileUtils.writeByteArrayToFile- especialmente quando você percebe encodedpode ser um byte[]também.)
mirabilos
101
Não há necessidade de usar o commons - a Sun envia um codificador base64 com Java. Você pode importá-lo como tal:
Onde encodedBytesé um java.lang.Stringou um java.io.InputStream. Apenas tome cuidado para que as sun.*classes não sejam "oficialmente suportadas" pela Sun.
EDIT: Quem sabia que essa seria a resposta mais controversa que eu já postaria? Eu sei que os pacotes sun. * Não são suportados ou garantidos para continuarem a existir, e eu sei sobre o Commons e o uso o tempo todo. No entanto, o pôster solicitava uma aula que fosse "incluída no Sun Java 6" e era isso que eu estava tentando responder. Concordo que o Commons é o melhor caminho a percorrer em geral.
EDIT 2: Como amir75 aponta abaixo, o Java 6+ é enviado com JAXB, que contém código suportado para codificar / decodificar o Base64. Por favor, veja a resposta de Jeremy Ross abaixo.
-1 - este é um código interno da Sun, NÃO faz parte do J2SE (não é portátil) e pode desaparecer a qualquer momento - a Sun diz explicitamente para NÃO usar suas bibliotecas internas no código do usuário
kdgregory
59
Verdade, daí o meu aviso no final.
MattK
20
Isso é para um projeto de curto prazo e é apenas um experimento e não deseja passar pelo processo de aprovação de uma nova biblioteca. Portanto, esta é a resposta correta para esta pergunta.
22713 Ryan P
44
Bzzt. Em um ambiente profissional, o uso de um recurso não suportado e não documentado nunca é a decisão correta. E em um ambiente corporativo, "experimentos" se tornam "código de produção", sem chance de consertar os hacks.
kdgregory
29
Em um departamento de pesquisa em que esse código é marcado como experimento e quando é marcado sempre é descartado, é a decisão correta.
Ryan P
55
Especificamente no Commons Codec : classe Base64para decode(byte[] array)ouencode(byte[] array)
Você pode vincular o texto 'Commons Codec' à página do projeto. Dessa forma, esta resposta seria melhor do que Kevin :)
mmutilva
1
Sei que essa é uma pergunta antiga, mas por que essa não é a resposta aceita? O codec comum não está incluído na maioria das instalações java e muito menos linhas de código a serem usadas do que lançando sua própria versão?
Li Haoyi
2
@LiHaoyi A pergunta foi feita por bibliotecas enviadas com o JDK da Sun, que não inclui nada do Commons.
Ti Strga
1
Pista falsa. Esses métodos não existem!
Nicolas Barbulesco
36
A goiaba agora possui a decodificação Base64 incorporada.
não é buggy! - leia os comentários do javadoc ... o parâmetro decode (..) é base64 String e não apenas qualquer String. byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));// => true
GeorgeK 5/05
9
Mais rápido e mais fácil? Reinventando a roda ?!
Nicolas Barbulesco
7
Fiz alguns testes comparando essa classe com o commons-codec e parece funcionar bem. Eu precisava de algo simples assim, porque só precisava da codificação base64 e não queria todo o material extra que o commons-codec fornece, obrigado.
Michael
2
Isso é confiável? Parece ser o mais fácil se você não deseja importar bibliotecas externas.
Felipe
2
Ele não funciona com bytes obtidos a partir AES algoritmo
shontauro
11
Aqui está minha própria implementação, se puder ser útil para alguém:
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(){}}
O MiGBase64 é fácil de usar, bem codificado e extremamente rápido. Boa descoberta, Imby.
Mukama
De acordo com esse benchmark, o MiGBase64 não é mais a implementação mais rápida e agora fica atrás do Apache Commons e do sun.misc.BASE64Decoder significativamente.
22413 Andrea Andrea
3
Essa é uma resposta tardia , mas Joshua Bloch comprometeu sua Base64classe (quando estava trabalhando para a Sun, ahem, Oracle) sob o java.util.prefspacote. Esta classe existe desde o JDK 1.4.
A implementação do Java 8 java.util.Base64não tem dependências de outras classes específicas do Java 8.
Não tenho certeza se isso funcionará para o projeto Java 6, mas é possível copiar e colar o Base64.javaarquivo em um projeto Java 7 e compilá-lo sem outra modificação além de importar java.util.Arrays e java.util.Objects.
Observe que o arquivo Base64.java é coberto pelo 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}
Em um código compilado com Java 7, mas potencialmente executando em uma versão java superior, parece útil detectar a presença de java.util.Base64classe e usar a abordagem melhor para a JVM dada mencionada em outras perguntas aqui.
Respostas:
A partir da v6, o Java SE é enviado com JAXB.
javax.xml.bind.DatatypeConverter
possui métodos estáticos que facilitam isso. VejaparseBase64Binary()
eprintBase64Binary()
.fonte
printBase64Binary(..)
método não executa a versão MIME do Base64 ( en.wikipedia.org/wiki/Base64#MIME ), enquanto as implementações particulares da Sun e do Commons usam isso. Especificamente, para String com mais de 76 caracteres, novas linhas são adicionadas. Eu não encontrei como configurar a implementação do JAXB para esse comportamento ... :-(A partir do Java 8 , há uma API oficialmente suportada para codificação e decodificação Base64. Com o tempo, isso provavelmente se tornará a opção padrão.
A API inclui a classe
java.util.Base64
e suas classes aninhadas. Ele suporta três tipos diferentes: básico, seguro de URL e MIME.Código de exemplo usando a codificação "básica":
A documentação para
java.util.Base64
inclui vários outros métodos para configurar codificadores e decodificadores e para usar diferentes classes como entradas e saídas (matrizes de bytes, seqüências de caracteres, ByteBuffers, fluxos java.io).fonte
final byte[] decoded = Base64.getMimeDecoder().decode(encoded);
lugar. Mas obrigada mesmo assim! (Nice com commons-ioFileUtils.readFileToByteArray
eFileUtils.writeByteArrayToFile
- especialmente quando você percebeencoded
pode ser umbyte[]
também.)Não há necessidade de usar o commons - a Sun envia um codificador base64 com Java. Você pode importá-lo como tal:
E então use-o assim:
Onde
encodedBytes
é umjava.lang.String
ou umjava.io.InputStream
. Apenas tome cuidado para que assun.*
classes não sejam "oficialmente suportadas" pela Sun.EDIT: Quem sabia que essa seria a resposta mais controversa que eu já postaria? Eu sei que os pacotes sun. * Não são suportados ou garantidos para continuarem a existir, e eu sei sobre o Commons e o uso o tempo todo. No entanto, o pôster solicitava uma aula que fosse "incluída no Sun Java 6" e era isso que eu estava tentando responder. Concordo que o Commons é o melhor caminho a percorrer em geral.
EDIT 2: Como amir75 aponta abaixo, o Java 6+ é enviado com JAXB, que contém código suportado para codificar / decodificar o Base64. Por favor, veja a resposta de Jeremy Ross abaixo.
fonte
Especificamente no Commons Codec : classe
Base64
paradecode(byte[] array)
ouencode(byte[] array)
fonte
A goiaba agora possui a decodificação Base64 incorporada.
Use BaseEncoding.base64 (). Decode ()
Quanto a lidar com espaço em branco possível no uso de entrada
BaseEncoding.base64().decode(CharMatcher.WHITESPACE.removeFrom(...));
Consulte esta discussão para obter mais informações
fonte
Minha solução é mais rápida e fácil.
fonte
byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));
// => trueAqui está minha própria implementação, se puder ser útil para alguém:
fonte
Como uma alternativa para
sun.misc.BASE64Decoder
ou bibliotecas não essenciais, vejajavax.mail.internet.MimeUtility.decode()
.Link com código completo: Codificar / Decodificar de / para Base64
fonte
Outra resposta tardia, mas meus testes de desempenho mostram que a implementação do codificador Base64 pelo Jetty é bastante rápida. Não é tão rápido quanto o MiGBase64, mas mais rápido que o iHarder Base64 .
Eu também fiz alguns benchmarks:
São corridas / s, portanto, quanto maior, melhor.
fonte
Dado um exemplo de codificação / decodificação de teste de javax.xml.bind.DatatypeConverter usando os métodos parseBase64Binary () e printBase64Binary (), referindo-se às respostas @ jeremy-ross e @ nightfirecat.
Resultado:
fonte
Se você prefere uma solução baseada em desempenho, pode usar o "MiGBase64"
http://migbase64.sourceforge.net/
fonte
Essa é uma resposta tardia , mas Joshua Bloch comprometeu sua
Base64
classe (quando estava trabalhando para a Sun, ahem, Oracle) sob ojava.util.prefs
pacote. Esta classe existe desde o JDK 1.4.Por exemplo
fonte
java.util.Base64
java.util.Base64
foi lançado no JDK 8 (e superior). Não existe em versões anteriores.Espero que isso ajude você:
Ou:
java.util.prefs.Base64
trabalha no localrt.jar
,Mas não está na lista branca da classe JRE
e não nas classes disponíveis não listadas na lista branca do GAE / J
Que pena!
PS. No Android, é fácil, porque isso
android.util.Base64
foi incluído desde o nível 8 da API do Android.fonte
Você pode gravar ou baixar o arquivo a partir da string Base64 codificada:
Trabalhou para mim e espero que você também ...
fonte
A implementação do Java 8
java.util.Base64
não tem dependências de outras classes específicas do Java 8.Não tenho certeza se isso funcionará para o projeto Java 6, mas é possível copiar e colar o
Base64.java
arquivo em um projeto Java 7 e compilá-lo sem outra modificação além de importar java.util.Arrays ejava.util.Objects
.Observe que o arquivo Base64.java é coberto pelo GNU GPL2
fonte
Eu usei
android.util.base64
isso funciona muito bem sem nenhuma dependência:Uso:
pacote com.test;
fonte
Usando Java 8 -
fonte
Você pode simplesmente tentar isso.
"Base64.getDecode ()" retorna um decodificador Base64 que pode ser decodificado. Então você precisa decodificar isso novamente usando ".decode ()"
fonte
Em um código compilado com Java 7, mas potencialmente executando em uma versão java superior, parece útil detectar a presença de
java.util.Base64
classe e usar a abordagem melhor para a JVM dada mencionada em outras perguntas aqui.Eu usei este código:
fonte
fonte