J'ai une image encodée en Base64. Quelle est la meilleure façon de décoder cela en Java? Espérons que nous n'utilisons que les bibliothèques incluses avec Sun Java 6.
Quel que soit le type d'application que vous utilisez (expérimentez ou non), c'est aussi simple que de créer un seul fichier Base64.java dans votre package d'utilitaires en utilisant le code ici: migbase64.sourceforge.net Regardez les graphiques de performances et notez la différence: 4 à 5 fois plus rapide.
javacoder
FYI: JEP 135 propose d'introduire une API standard et détectable pour cela dans la plate-forme Java.
Cependant, il semble que la printBase64Binary(..)méthode ne fasse pas la version MIME de Base64 ( en.wikipedia.org/wiki/Base64#MIME ), tandis que les implémentations privées de Sun et de Commons l'utilisent. Plus précisément, pour les chaînes de plus de 76 caractères, des sauts de ligne sont ajoutés. Je n'ai pas trouvé comment configurer l'implémentation de JAXB pour ce comportement ... :-(
KLE
7
cependant, la mise en œuvre de Sun ignorera les nouvelles lignes. Ils sont donc compatibles.
Esben Skov Pedersen
9
Attention! parseBase64Binary sautera silencieusement les caractères invalides et ne vérifiera pas la validité de base64. Il est préférable d'utiliser Commons Codec ou Guava Base64. Notez que Guava rejette les sauts de ligne et les caractères d'espacement, vous devez donc analyser les chaînes avec des espaces omis: BaseEncoding.base64 (). Decode (s.replaceAll ("\\ s", ""))
Martin Vysny
9
Faites attention. Cette fonction ne fonctionne pas avec des données supérieures à 65 000. (version Java 1.6)
Hüseyin Yağlı
5
Ne l'utilisez pas, car vous rencontrerez des problèmes dans jdk 9: java.lang.NoClassDefFoundError (javax / xml / bind / DatatypeConverter)
rupashka
381
Depuis Java 8 , il existe une API officiellement prise en charge pour l'encodage et le décodage Base64. Avec le temps, cela deviendra probablement le choix par défaut.
L'API inclut la classe java.util.Base64et ses classes imbriquées. Il prend en charge trois versions différentes: de base, sans danger pour les URL et MIME.
La documentation dejava.util.Base64 inclut plusieurs autres méthodes pour configurer les encodeurs et décodeurs, et pour utiliser différentes classes comme entrées et sorties (tableaux d'octets, chaînes, ByteBuffers, flux java.io).
J'utilise Java 8. Est-ce l'approche recommandée si j'utilise Java 8?
JohnMerlino
4
@JohnMerlino si la compatibilité avec les anciennes versions de Java n'est pas requise, je recommanderais d'utiliser cette API car le JRE a une politique de compatibilité plus forte que la plupart des bibliothèques. De plus, étant inclus dans le JRE, il ne limite pas vos dépendances de quelque manière que ce soit.
Andrea
4
Java 7 est EOLed, Java 9 arrive, c'est la bonne réponse pour moi!
eskatos
1
Presque bon: cela n'accepte que les flux bruts base64, pas les fichiers base64. J'ai dû utiliser à la final byte[] decoded = Base64.getMimeDecoder().decode(encoded);place. Mais merci quand même! (Sympa avec commons-io FileUtils.readFileToByteArrayet FileUtils.writeByteArrayToFile- surtout quand on se rend compte qu'il encodedpeut aussi en être un byte[].)
mirabilos
101
Pas besoin d'utiliser des communs - Sun fournit un encodeur base64 avec Java. Vous pouvez l'importer tel quel:
Où encodedBytesest soit a, java.lang.Stringsoit a java.io.InputStream. Sachez juste que lesun.* cours ne sont pas "officiellement supportés" par Sun.
ÉDITER: Qui savait que ce serait la réponse la plus controversée que j'aie jamais publiée? Je sais que les packages sun. * Ne sont pas pris en charge ou garantis pour continuer d'exister, et je connais Commons et l'utilise tout le temps. Cependant, l'affiche a demandé un cours qui était "inclus avec Sun Java 6", et c'est ce que j'essayais de répondre. Je suis d'accord que Commons est la meilleure façon de procéder en général.
EDIT 2: Comme le souligne amir75 ci-dessous, Java 6+ est livré avec JAXB, qui contient le code pris en charge pour encoder / décoder Base64. Veuillez voir la réponse de Jeremy Ross ci-dessous.
-1 - il s'agit d'un code Sun interne, ne fait PAS partie de J2SE (il n'est pas portable) et peut disparaître à tout moment - Sun dit explicitement de NE PAS utiliser ses bibliothèques internes dans le code utilisateur
kdgregory
59
C'est vrai, d'où mon avertissement à la fin.
MattK
20
Il s'agit d'un projet à court terme et n'est qu'une expérience et je ne veux pas passer par le processus d'approbation d'une nouvelle bibliothèque. C'est donc la bonne réponse à cette question.
Ryan P
44
Bzzt. Dans un environnement professionnel, l'utilisation d'une fonctionnalité non prise en charge et non documentée n'est jamais la bonne décision. Et dans un environnement d'entreprise, les «expériences» deviennent des «codes de production» sans aucune chance de corriger les hacks.
kdgregory
29
Dans un département de recherche où ce code est marqué comme expérience et quand il est toujours mis au rebut, c'est la bonne décision.
Ryan P
55
Plus précisément dans le codec Commons : classe Base64vers decode(byte[] array)ouencode(byte[] array)
Vous pouvez lier le texte «Commons Codec» à la page du projet. De cette façon, cette réponse serait meilleure que celle de Kevin :)
mmutilva
1
Je sais que c'est une vieille question, mais pourquoi n'est-ce pas la réponse acceptée? Le codec commun n'est-il pas inclus avec la plupart des installations java, et beaucoup moins de lignes de code à utiliser que de rouler votre propre version?
Li Haoyi
2
@LiHaoyi La question demandait les bibliothèques livrées avec le JDK de Sun, qui n'inclut rien de Commons.
Guava 14 est toujours un candidat à la sortie, mais cela obtient toujours mon vote positif - au moment où il atteint une position décente, il devrait être en or :-)
Peter Becker
1
Le décodeur base64 de goyave rejette les caractères de nouvelle ligne et d'espace, vous devez donc les supprimer au préalable.
Martin Vysny
34
Ma solution est la plus rapide et la plus simple.
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;}}
ce n'est pas buggy! - lire les commentaires javadoc ... le paramètre de décodage (..) est une chaîne base64 et pas n'importe quelle chaîne. byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));// => vrai
GeorgeK
9
Le plus rapide et le plus simple ?? Réinventer la roue ?!
Nicolas Barbulesco
7
J'ai effectué des tests en comparant cette classe avec le codec commun et cela semble fonctionner correctement. J'avais besoin de quelque chose de simple comme ça parce que je n'avais besoin que d'un encodage base64 et je ne voulais pas toutes les choses supplémentaires fournies par le codec commun, merci.
Michael
2
Est-ce confiant? Cela semble être le plus simple si vous ne souhaitez pas importer de bibliothèques externes.
Felipe
2
cela ne fonctionne pas avec les octets obtenus à partir de l'algorithme AES
shontauro
11
Voici ma propre implémentation, si elle peut être utile à quelqu'un:
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 est facile à utiliser, bien codé et extrêmement rapide. Belle trouvaille, Imby.
mukama
Selon cette référence, MiGBase64 n'est plus l'implémentation la plus rapide, et maintenant elle est considérablement en retard sur Apache Commons et sun.misc.BASE64Decoder.
Andrea
3
C'est une réponse tardive , mais Joshua Bloch a engagé sa Base64classe (quand il travaillait pour Sun, ahem, Oracle) dans le cadre du java.util.prefspackage. Cette classe existait depuis JDK 1.4.
L'implémentation Java 8 de java.util.Base64 n'a pas de dépendances sur d'autres classes spécifiques à Java 8.
Je ne sais pas si cela fonctionnera pour le projet Java 6, mais il est possible de copier et coller le Base64.javafichier dans un projet Java 7 et de le compiler sans autre modification que l'importation de java.util.Arrays etjava.util.Objects .
Notez que le fichier Base64.java est couvert par la 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}
Dans un code compilé avec Java 7 mais fonctionnant potentiellement dans une version java supérieure, il semble utile de détecter la présence de java.util.Base64 classe et d'utiliser la meilleure approche pour la JVM donnée mentionnée dans d'autres questions ici.
Réponses:
Depuis la v6, Java SE est livré avec JAXB.
javax.xml.bind.DatatypeConverter
a des méthodes statiques qui rendent cela facile. VoirparseBase64Binary()
etprintBase64Binary()
.la source
printBase64Binary(..)
méthode ne fasse pas la version MIME de Base64 ( en.wikipedia.org/wiki/Base64#MIME ), tandis que les implémentations privées de Sun et de Commons l'utilisent. Plus précisément, pour les chaînes de plus de 76 caractères, des sauts de ligne sont ajoutés. Je n'ai pas trouvé comment configurer l'implémentation de JAXB pour ce comportement ... :-(Depuis Java 8 , il existe une API officiellement prise en charge pour l'encodage et le décodage Base64. Avec le temps, cela deviendra probablement le choix par défaut.
L'API inclut la classe
java.util.Base64
et ses classes imbriquées. Il prend en charge trois versions différentes: de base, sans danger pour les URL et MIME.Exemple de code utilisant l'encodage "de base":
La documentation de
java.util.Base64
inclut plusieurs autres méthodes pour configurer les encodeurs et décodeurs, et pour utiliser différentes classes comme entrées et sorties (tableaux d'octets, chaînes, ByteBuffers, flux java.io).la source
final byte[] decoded = Base64.getMimeDecoder().decode(encoded);
place. Mais merci quand même! (Sympa avec commons-ioFileUtils.readFileToByteArray
etFileUtils.writeByteArrayToFile
- surtout quand on se rend compte qu'ilencoded
peut aussi en être unbyte[]
.)Pas besoin d'utiliser des communs - Sun fournit un encodeur base64 avec Java. Vous pouvez l'importer tel quel:
Et puis utilisez-le comme ceci:
Où
encodedBytes
est soit a,java.lang.String
soit ajava.io.InputStream
. Sachez juste que lesun.*
cours ne sont pas "officiellement supportés" par Sun.ÉDITER: Qui savait que ce serait la réponse la plus controversée que j'aie jamais publiée? Je sais que les packages sun. * Ne sont pas pris en charge ou garantis pour continuer d'exister, et je connais Commons et l'utilise tout le temps. Cependant, l'affiche a demandé un cours qui était "inclus avec Sun Java 6", et c'est ce que j'essayais de répondre. Je suis d'accord que Commons est la meilleure façon de procéder en général.
EDIT 2: Comme le souligne amir75 ci-dessous, Java 6+ est livré avec JAXB, qui contient le code pris en charge pour encoder / décoder Base64. Veuillez voir la réponse de Jeremy Ross ci-dessous.
la source
Plus précisément dans le codec Commons : classe
Base64
versdecode(byte[] array)
ouencode(byte[] array)
la source
La goyave intègre désormais le décodage Base64.
Utilisez BaseEncoding.base64 (). Decode ()
Quant au traitement des espaces blancs possibles lors de l'utilisation des entrées
BaseEncoding.base64().decode(CharMatcher.WHITESPACE.removeFrom(...));
Voir cette discussion pour plus d'informations
la source
Ma solution est la plus rapide et la plus simple.
la source
byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));
// => vraiVoici ma propre implémentation, si elle peut être utile à quelqu'un:
la source
Comme alternative aux
sun.misc.BASE64Decoder
bibliothèques ou non-core, regardezjavax.mail.internet.MimeUtility.decode()
.Lien avec le code complet: encoder / décoder vers / depuis Base64
la source
Une autre réponse tardive, mais mon analyse comparative montre que la mise en œuvre de Jetty de l' encodeur Base64 est assez rapide. Pas aussi rapide que MiGBase64 mais plus rapide que iHarder Base64 .
J'ai aussi fait quelques benchmarks:
Ce sont des runs / sec donc plus c'est mieux.
la source
Etant donné un essai exemple de codage / décodage de javax.xml.bind.DatatypeConverter en utilisant des méthodes parseBase64Binary () et printBase64Binary () se référant à @ jeremy-ross et réponse @nightfirecat.
Résultat:
la source
Si vous préférez une solution basée sur les performances, vous pouvez utiliser "MiGBase64"
http://migbase64.sourceforge.net/
la source
C'est une réponse tardive , mais Joshua Bloch a engagé sa
Base64
classe (quand il travaillait pour Sun, ahem, Oracle) dans le cadre dujava.util.prefs
package. Cette classe existait depuis JDK 1.4.Par exemple
la source
java.util.Base64
java.util.Base64
été publié dans JDK 8 (et supérieur). Il n'existe pas sur les versions antérieures.J'espère que cela vous aidera:
Ou:
java.util.prefs.Base64
travaille sur localrt.jar
,Mais ce n'est pas dans la liste blanche de la classe JRE
et pas dans les classes disponibles non répertoriées dans la liste blanche GAE / J
Quel dommage!
PS. Dans Android, c'est facile car cela
android.util.Base64
a été inclus depuis Android API niveau 8.la source
Vous pouvez écrire ou télécharger un fichier à partir d'une chaîne Base64 encodée:
A travaillé pour moi et j'espère pour vous aussi ...
la source
L'implémentation Java 8 de
java.util.Base64
n'a pas de dépendances sur d'autres classes spécifiques à Java 8.Je ne sais pas si cela fonctionnera pour le projet Java 6, mais il est possible de copier et coller le
Base64.java
fichier dans un projet Java 7 et de le compiler sans autre modification que l'importation de java.util.Arrays etjava.util.Objects
.Notez que le fichier Base64.java est couvert par la GNU GPL2
la source
J'ai utilisé
android.util.base64
cela fonctionne assez bien sans aucune dépendance:Usage:
package com.test;
la source
Utilisation de Java 8 -
la source
Vous pouvez simplement essayer ceci.
"Base64.getDecode ()" renvoie un décodeur Base64 qui peut être décodé. Ensuite, vous devez décoder à nouveau en utilisant ".decode ()"
la source
Dans un code compilé avec Java 7 mais fonctionnant potentiellement dans une version java supérieure, il semble utile de détecter la présence de
java.util.Base64
classe et d'utiliser la meilleure approche pour la JVM donnée mentionnée dans d'autres questions ici.J'ai utilisé ce code:
la source
la source