Mam obraz zakodowany w standardzie Base64. Jaki jest najlepszy sposób na odkodowanie tego w Javie? Mam nadzieję, że używamy tylko bibliotek zawartych w Sun Java 6.
Bez względu na to, jakiego rodzaju aplikacji używasz (eksperymentuj lub nie), jest to tak proste, jak utworzenie jednego pliku Base64.java w pakiecie utils za pomocą kodu tutaj: migbase64.sourceforge.net Spójrz na wykresy wydajności i zauważ różnicę: 4-5 razy szybciej.
javacoder
FYI: JEP 135 proponuje wprowadzenie standardowego, wykrywalnego API w tym celu na platformie Java.
Wydaje się jednak, że printBase64Binary(..)metoda nie obsługuje wersji MIME Base64 ( en.wikipedia.org/wiki/Base64#MIME ), podczas gdy prywatne implementacje Sun i Commons używają tego. W szczególności w przypadku ciągu większego niż 76 znaków dodawane są znaki nowej linii. Nie znalazłem sposobu na skonfigurowanie implementacji JAXB dla tego zachowania ... :-(
KLE
7
jednak implementacja słońca zignoruje nowe linie. Więc są kompatybilne.
Esben Skov Pedersen
9
Ostrzeżenie! parseBase64Binary po cichu pominie niepoprawne znaki i nie sprawdzi poprawności base64. Lepiej jest użyć Commons Codec lub Guava Base64. Zauważ, że Guava odrzuca znaki nowej linii i białe znaki, więc musisz przeanalizować ciągi znaków z pominiętymi białymi znakami: BaseEncoding.base64 (). Decode (s.replaceAll ("\\ s", ""))
Martin Vysny
9
Bądź ostrożny. Ta funkcja nie działa z danymi dłuższymi niż 65000. (java wersja 1.6)
Hüseyin Yağlı 21.09.2013
5
Nie używaj go, ponieważ będziesz mieć problemy w JDK 9: java.lang.NoClassDefFoundError (javax / xml / bind / DatatypeConverter)
rupashka
381
Od wersji Java 8 istnieje oficjalnie obsługiwany interfejs API do kodowania i dekodowania Base64. Z czasem stanie się to domyślnym wyborem.
Interfejs API obejmuje klasę java.util.Base64i jej zagnieżdżone klasy. Obsługuje trzy różne smaki: podstawowy, bezpieczny pod adresem URL i MIME.
Przykładowy kod wykorzystujący kodowanie „podstawowe”:
Dokumentacjajava.util.Base64 zawiera jeszcze kilka sposobów konfigurowania koderów i dekoderów i do użycia różnych klasach wejść i wyjść (tablice bajtów, sznurki, ByteBuffers strumienie java.io).
Używam Java 8. Czy jest to zalecane podejście w przypadku korzystania z Java 8?
JohnMerlino
4
@JohnMerlino, jeśli zgodność ze starszymi wersjami Java nie jest wymagana, zaleciłbym użycie tego interfejsu API, ponieważ środowisko JRE ma silniejszą politykę zgodności niż większość bibliotek. Ponadto, zawarte w środowisku JRE, nie ogranicza w żaden sposób twoich zależności.
Andrea
4
Java 7 jest EOLed, Java 9 nadchodzi, to jest odpowiednia odpowiedź dla mnie!
eskatos
1
Prawie dobrze: akceptuje tylko surowe strumienie base64, a nie pliki base64. Musiałem final byte[] decoded = Base64.getMimeDecoder().decode(encoded);zamiast tego użyć . Ale i tak dzięki! (Miło z commons-io FileUtils.readFileToByteArrayi FileUtils.writeByteArrayToFile- szczególnie, gdy zdajesz sobie sprawę, że encodedmoże być byte[]również.)
mirabilos
101
Nie ma potrzeby używania wspólnego - Sun dostarcza koder base64 z Javą. Możesz zaimportować go jako taki:
Gdzie encodedBytesjest albo a java.lang.Stringalbo a java.io.InputStream. Uwaga: sun.*klasy nie są „oficjalnie wspierane” przez Sun.
EDYCJA: Kto wiedział, że będzie to najbardziej kontrowersyjna odpowiedź, jaką kiedykolwiek opublikowałem? Wiem, że pakiety sun. * Nie są obsługiwane ani gwarantowane, aby istniały dalej, i wiem o Commons i używam go cały czas. Jednak plakat poprosił o zajęcia, które były „zawarte w Sun Java 6” i na to właśnie starałem się odpowiedzieć. Zgadzam się, że Commons to ogólnie najlepsza droga.
EDYCJA 2: Jak wskazuje amir75 poniżej, Java 6+ jest dostarczana z JAXB, który zawiera obsługiwany kod do kodowania / dekodowania Base64. Zobacz odpowiedź Jeremy Ross poniżej.
-1 - jest to wewnętrzny kod Sun, NIE jest częścią J2SE (nie jest przenośny) i może zniknąć w dowolnym momencie - Sun wyraźnie mówi, aby NIE używać swoich wewnętrznych bibliotek w kodzie użytkownika
kdgregory
59
To prawda, stąd moje zastrzeżenie na końcu.
MattK
20
To jest projekt krótkoterminowy i jest tylko eksperymentem i nie chcę przechodzić przez proces zatwierdzania nowej biblioteki. To jest poprawna odpowiedź na to pytanie.
Ryan P
44
Bzzt. W środowisku profesjonalnym korzystanie z nieobsługiwanej, nieudokumentowanej funkcji nigdy nie jest właściwą decyzją. A w środowisku korporacyjnym „eksperymenty” stają się „kodem produkcyjnym” bez szans na naprawienie włamań.
kdgregory
29
W dziale badawczym, w którym ten kod jest oznaczony jako eksperyment, a gdy jest oznaczony, zawsze zostaje skasowany, jest to właściwa decyzja.
Ryan P
55
W szczególności w Commons Codec : class Base64to decode(byte[] array)orencode(byte[] array)
Możesz połączyć tekst „Commons Codec” ze stroną projektu. W ten sposób ta odpowiedź byłaby lepsza niż odpowiedź Kevina :)
mmutilva
1
Wiem, że to stare pytanie, ale dlaczego nie jest to zaakceptowana odpowiedź? Czy wspólny kodek nie jest dołączony do większości instalacji Java i ma o wiele mniej wierszy kodu do użycia niż tworzenie własnej wersji?
Li Haoyi,
2
@LiHaoyi Pytanie zadane dla bibliotek dostarczanych z JDK firmy Sun, które nie obejmują niczego z Commons.
to nie jest buggy! - przeczytaj komentarze javadoc ... parametrem dekodowania (..) jest ciąg base64, a nie dowolny ciąg. byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));// => true
GeorgeK
9
Najszybszy i najłatwiejszy? Reinventing koła?
Nicolas Barbulesco
7
Przeprowadziłem kilka testów porównujących tę klasę ze wspólnym kodekiem i wydaje się, że działa OK. Potrzebowałem czegoś prostego, ponieważ potrzebowałem tylko kodowania base64 i nie chciałem wszystkich dodatkowych rzeczy, które zapewnia wspólny kodek, dzięki.
Michael
2
Czy to jest ufne? Wydaje się to najłatwiejsze, jeśli nie chcesz importować bibliotek zewnętrznych.
Felipe
2
nie działa z bajtami uzyskanymi z algorytmu AES
shontauro,
11
Oto moja własna implementacja, jeśli może być przydatna dla kogoś:
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 jest łatwy w użyciu, dobrze kodowany i błyskawicznie szybki. Niezłe znalezisko, Imby.
mukama,
Według tego testu porównawczego MiGBase64 nie jest już najszybszą implementacją, a teraz znacznie ustępuje zarówno Apache Commons, jak i sun.misc.BASE64Decoder.
Andrea
3
To późna odpowiedź, ale Joshua Bloch zaangażował swoją Base64klasę (kiedy pracował dla Sun, ahem, Oracle) w ramach java.util.prefspakietu. Ta klasa istniała od JDK 1.4.
Implementacja Java 8 java.util.Base64nie ma zależności od innych klas specyficznych dla Java 8.
Nie jestem pewien, czy to zadziała dla projektu Java 6, ale można skopiować i wkleić Base64.javaplik do projektu Java 7 i skompilować go bez modyfikacji innych niż importowanie java.util.Arrays i java.util.Objects.
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}
W kodzie skompilowanym z Javą 7, ale potencjalnie działającym w wyższej wersji java, przydatne wydaje się wykrycie obecności java.util.Base64klasy i zastosowanie najlepszego podejścia dla danej JVM wspomnianej w innych pytaniach tutaj.
Odpowiedzi:
Od wersji 6 Java SE jest dostarczana z JAXB.
javax.xml.bind.DatatypeConverter
ma statyczne metody, które to ułatwiają. ZobaczparseBase64Binary()
iprintBase64Binary()
.źródło
printBase64Binary(..)
metoda nie obsługuje wersji MIME Base64 ( en.wikipedia.org/wiki/Base64#MIME ), podczas gdy prywatne implementacje Sun i Commons używają tego. W szczególności w przypadku ciągu większego niż 76 znaków dodawane są znaki nowej linii. Nie znalazłem sposobu na skonfigurowanie implementacji JAXB dla tego zachowania ... :-(Od wersji Java 8 istnieje oficjalnie obsługiwany interfejs API do kodowania i dekodowania Base64. Z czasem stanie się to domyślnym wyborem.
Interfejs API obejmuje klasę
java.util.Base64
i jej zagnieżdżone klasy. Obsługuje trzy różne smaki: podstawowy, bezpieczny pod adresem URL i MIME.Przykładowy kod wykorzystujący kodowanie „podstawowe”:
Dokumentacja
java.util.Base64
zawiera jeszcze kilka sposobów konfigurowania koderów i dekoderów i do użycia różnych klasach wejść i wyjść (tablice bajtów, sznurki, ByteBuffers strumienie java.io).źródło
final byte[] decoded = Base64.getMimeDecoder().decode(encoded);
zamiast tego użyć . Ale i tak dzięki! (Miło z commons-ioFileUtils.readFileToByteArray
iFileUtils.writeByteArrayToFile
- szczególnie, gdy zdajesz sobie sprawę, żeencoded
może byćbyte[]
również.)Nie ma potrzeby używania wspólnego - Sun dostarcza koder base64 z Javą. Możesz zaimportować go jako taki:
A następnie użyj tego w ten sposób:
Gdzie
encodedBytes
jest albo ajava.lang.String
albo ajava.io.InputStream
. Uwaga:sun.*
klasy nie są „oficjalnie wspierane” przez Sun.EDYCJA: Kto wiedział, że będzie to najbardziej kontrowersyjna odpowiedź, jaką kiedykolwiek opublikowałem? Wiem, że pakiety sun. * Nie są obsługiwane ani gwarantowane, aby istniały dalej, i wiem o Commons i używam go cały czas. Jednak plakat poprosił o zajęcia, które były „zawarte w Sun Java 6” i na to właśnie starałem się odpowiedzieć. Zgadzam się, że Commons to ogólnie najlepsza droga.
EDYCJA 2: Jak wskazuje amir75 poniżej, Java 6+ jest dostarczana z JAXB, który zawiera obsługiwany kod do kodowania / dekodowania Base64. Zobacz odpowiedź Jeremy Ross poniżej.
źródło
W szczególności w Commons Codec : class
Base64
todecode(byte[] array)
orencode(byte[] array)
źródło
Guava ma teraz wbudowane dekodowanie Base64.
Użyj funkcji BaseEncoding.base64 (). Decode ()
Co do radzenia sobie z możliwymi spacjami w użyciu danych wejściowych
BaseEncoding.base64().decode(CharMatcher.WHITESPACE.removeFrom(...));
Zobacz tę dyskusję, aby uzyskać więcej informacji
źródło
Moje rozwiązanie jest najszybsze i najłatwiejsze.
źródło
byte[] b1 = {1,2,3}; byte[] b2 = decode(encode(b1)); System.out.println(Arrays.equals( b1, b2 ));
// => trueOto moja własna implementacja, jeśli może być przydatna dla kogoś:
źródło
Jako alternatywę
sun.misc.BASE64Decoder
dla bibliotek innych niż rdzenia, spójrz najavax.mail.internet.MimeUtility.decode()
.Link z pełnym kodem: Koduj / Dekoduj do / z Base64
źródło
Kolejna późna odpowiedź, ale moje testy porównawcze pokazują, że implementacja kodera Base64 przez Jetty jest dość szybka. Nie tak szybki jak MiGBase64, ale szybszy niż iHarder Base64 .
Zrobiłem też kilka testów porównawczych:
Są to przebiegi na sekundę, więc im wyższa, tym lepiej.
źródło
Biorąc pod uwagę badanie przykład kodowania / dekodowania javax.xml.bind.DatatypeConverter użyciu metody parseBase64Binary () i printBase64Binary () odnosząc się do @ jeremy-Ross i @nightfirecat odpowiedź.
Wynik:
źródło
Jeśli wolisz rozwiązanie oparte na wydajności, możesz użyć „MiGBase64”
http://migbase64.sourceforge.net/
źródło
To późna odpowiedź, ale Joshua Bloch zaangażował swoją
Base64
klasę (kiedy pracował dla Sun, ahem, Oracle) w ramachjava.util.prefs
pakietu. Ta klasa istniała od JDK 1.4.Na przykład
źródło
java.util.Base64
java.util.Base64
został wydany w JDK 8 (i wyżej). Nie istnieje we wcześniejszych wersjach.Mam nadzieję, że to pomoże ci:
Lub:
java.util.prefs.Base64
Działa na poziomie lokalnymrt.jar
,Ale nie ma go na Białej liście klas JRE
i nie w Dostępne klasy niewymienione na białej liście GAE / J
Jaka szkoda!
PS. W
android.util.Base64
Androidzie jest to łatwe, ponieważ zostało to uwzględnione od poziomu 8 interfejsu API Androida.źródło
Możesz zapisać lub pobrać plik z zakodowanego ciągu Base64:
Pracował dla mnie i mam nadzieję, że również dla ciebie ...
źródło
Implementacja Java 8
java.util.Base64
nie ma zależności od innych klas specyficznych dla Java 8.Nie jestem pewien, czy to zadziała dla projektu Java 6, ale można skopiować i wkleić
Base64.java
plik do projektu Java 7 i skompilować go bez modyfikacji innych niż importowanie java.util.Arrays ijava.util.Objects
.Uwaga: plik Base64.java jest objęty GNU GPL2
źródło
Użyłem,
android.util.base64
że działa całkiem dobrze bez żadnych zależności:Stosowanie:
pakiet com.test;
źródło
Korzystanie z Java 8 -
źródło
Możesz po prostu spróbować tego.
„Base64.getDecode ()” zwraca dekoder Base64, który można dekodować. Następnie musisz go ponownie zdekodować za pomocą „.decode ()”
źródło
W kodzie skompilowanym z Javą 7, ale potencjalnie działającym w wyższej wersji java, przydatne wydaje się wykrycie obecności
java.util.Base64
klasy i zastosowanie najlepszego podejścia dla danej JVM wspomnianej w innych pytaniach tutaj.Użyłem tego kodu:
źródło
źródło