Kodowanie jako Base64 w Javie

317

Muszę zakodować niektóre dane w kodowaniu Base64 w Javie. Jak mogę to zrobić? Jak nazywa się klasa udostępniająca koder Base64?


Próbowałem skorzystać z sun.misc.BASE64Encoderklasy, ale bez powodzenia. Mam następujący wiersz kodu Java 7:

wr.write(new sun.misc.BASE64Encoder().encode(buf));

Używam Eclipse. Zaćmienie zaznacza tę linię jako błąd. Zaimportowałem wymagane biblioteki:

import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder;

Ale znowu oba są wyświetlane jako błędy. Znalazłem tutaj podobny post .

Użyłem Apache Commons jako rozwiązania sugerowanego przez:

import org.apache.commons.*;

i importowanie plików JAR pobranych z: http://commons.apache.org/codec/

Ale problem nadal istnieje. Zaćmienie nadal pokazuje wspomniane wcześniej błędy. Co powinienem zrobić?

Jury A.
źródło
7
Moja rada: przeczytaj komunikat o błędzie i spróbuj zrozumieć, co mówi.
JB Nizet,
27
Nie należy używać klas podsun.**
onon 15
16
Nie są one częścią publicznego API; mogą zostać zmienione, usunięte lub cokolwiek innego bez uprzedzenia. Niektóre z nich mogą mieć charakter eksperymentalny lub po prostu nie mieć jakości produkcyjnej. oracle.com/technetwork/java/faq-sun-packages-142232.html
onon15
5
Lub użyj JAXB DatatypeConverter, który jest standardowo zawarty w Javie 6 i nowszych.
Ian Roberts
9
java.util.Base64 jest dostępny w Javie 8
kamera douszna

Odpowiedzi:

621

Musisz zmienić import swojej klasy:

import org.apache.commons.codec.binary.Base64;

A następnie zmień klasę, aby korzystała z klasy Base64.

Oto przykładowy kod:

byte[] encodedBytes = Base64.encodeBase64("Test".getBytes());
System.out.println("encodedBytes " + new String(encodedBytes));
byte[] decodedBytes = Base64.decodeBase64(encodedBytes);
System.out.println("decodedBytes " + new String(decodedBytes));

Przeczytaj, dlaczego nie powinieneś używać pakietów sun. * .


Aktualizacja (16.12.2016)

Możesz teraz używać java.util.Base64z Javą 8. Najpierw zaimportuj go w zwykły sposób:

import java.util.Base64;

Następnie użyj metod statycznych Base64 w następujący sposób:

byte[] encodedBytes = Base64.getEncoder().encode("Test".getBytes());
System.out.println("encodedBytes " + new String(encodedBytes));
byte[] decodedBytes = Base64.getDecoder().decode(encodedBytes);
System.out.println("decodedBytes " + new String(decodedBytes));

Jeśli chcesz bezpośrednio zakodować ciąg i uzyskać wynik jako zakodowany ciąg, możesz użyć tego:

String encodeBytes = Base64.getEncoder().encodeToString((userName + ":" + password).getBytes());

Aby uzyskać więcej informacji, zobacz dokumentację Java dla Base64 .

Szczery
źródło
Czy muszę pobrać jakiś pakiet zewnętrzny, aby to działało? Jeśli tak to jakie?
przerwane
2
Nie, nie musisz niczego pobierać
afaik
16
org.apache.commons.codec.binary.Base64 nie wygląda jak biblioteka domyślna. Myślę, że musisz do tego dołączyć wspólne apache. Dobrze?
Robert Reiz
@Frank Dekodowanie bajtów naraz powoduje błąd OutOfMemory. Każdy pomysł przetwarza go w buforze
xyz
225

Skorzystaj z nigdy nie spóźnionej klasy Java 8, aby dołączyć do zabawy: java.util.Base64

new String(Base64.getEncoder().encode(bytes));
bratan
źródło
11
Chociaż jest to trywialny komentarz, zauważ, że jeśli go użyjesz, nie będziesz kompatybilny ze starszymi wersjami Javy, które są (przynajmniej w tym momencie) prawdopodobnie znacznie bardziej rozpowszechnione.
dcoder
Chciałbym również wybrać klasę Java 8 jest możliwa. Obecnie pracuję nad klasą, aby usunąć bibliotekę apache commons z naszego wiosennego projektu. Większość rzeczy można łatwo zastąpić metodą z bibliotek Spring lub jdk.
Adrian Cosma
68

W Javie 8 można to zrobić jako: Base64.getEncoder (). EncodeToString (string.getBytes (StandardCharsets.UTF_8))

Oto krótki, samodzielny kompletny przykład:

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Temp {
    public static void main(String... args) throws Exception {
        final String s = "old crow medicine show";
        final byte[] authBytes = s.getBytes(StandardCharsets.UTF_8);
        final String encoded = Base64.getEncoder().encodeToString(authBytes);
        System.out.println(s + " => " + encoded);
    }
}

Wynik:

old crow medicine show => b2xkIGNyb3cgbWVkaWNpbmUgc2hvdw==
Kirby
źródło
3
Dlaczego w standardowej bibliotece Java nie ma stałych Charset, och dlaczego ?!
Łukasz Wiktor
4
Dobre pytanie, Łukasz! Właściwie są. Zapomniałem! java.nio.charset.StandardCharsets. Zmienię swoją odpowiedź. Zobacz stackoverflow.com/questions/1684040/…
Kirby
67

Możesz także dokonać konwersji przy użyciu kodowania Base64. Aby to zrobić, możesz użyć javax.xml.bind.DatatypeConverter#printBase64Binarymetody.

Na przykład:

byte[] salt = new byte[] { 50, 111, 8, 53, 86, 35, -19, -47 };
System.out.println(DatatypeConverter.printBase64Binary(salt));
Stinepike
źródło
4
Podczas gdy to działa, dokumentacja wyraźnie stwierdza: Interfejs DatatypeConverterInterface jest tylko do użytku dostawcy JAXB.
gebirgsbärbel,
11
Wydaje mi się, że @gebirgsbaerbel jest niepoprawna, metoda printX () i parseX () może być używana przez dowolną, jedyną rzeczą, która dotyczy tylko JAXB, jest setDatatypeConverter()metoda (którą następnie należy wywołać dla dostawców JAXB).
PhoneixS,
9
Ostatecznie klasa Base64 z Java 8 będzie droga. Ale jeśli w międzyczasie musisz celować w Javę 7, to rozwiązanie jest dobre, ponieważ nie opiera się na bibliotekach zewnętrznych.
dana
4
To nie działa w Javie 9. Gorzej, kod skompilowany dla Java 7 przy użyciu javax.xml.bind. * Zawiedzie w czasie wykonywania w Javie 9.
Stephen M - strajk -
21

Google Guava to kolejny wybór do kodowania i dekodowania danych Base64:

Konfiguracja POM:

<dependency>
   <artifactId>guava</artifactId>
   <groupId>com.google.guava</groupId>
   <type>jar</type>
   <version>14.0.1</version>
</dependency>

Przykładowy kod:

String inputContent = "Hello Việt Nam";
String base64String = BaseEncoding.base64().encode(inputContent.getBytes("UTF-8"));

// Decode
System.out.println("Base64:" + base64String); // SGVsbG8gVmnhu4d0IE5hbQ==
byte[] contentInBytes = BaseEncoding.base64().decode(base64String);
System.out.println("Source content: " + new String(contentInBytes, "UTF-8")); // Hello Việt Nam
Chociaż
źródło
10

Zaćmienie wyświetla błąd / ostrzeżenie, ponieważ próbujesz użyć klas wewnętrznych, które są specyficzne dla dostawcy JDK, a nie są częścią publicznego interfejsu API. Jakarta Commons zapewnia własną implementację kodeków base64, które oczywiście znajdują się w innym pakiecie. Usuń te importy i pozwól Eclipse zaimportować dla ciebie odpowiednie klasy Commons.

Marko Topolnik
źródło
Projekt Dżakarta już nie istnieje . Został on zmiksowany i dopasowany (a nazwa została ponownie użyta w Javie EE ). Czy potrafisz zaktualizować swoją odpowiedź i podać jakieś referencje? Na przykład, jest to obecnie klasa Base64worg.apache.commons.codec.binary ? Czy w tym kontekście jest to już Apache Commons ?
Peter Mortensen
9

Aby to przekonwertować, potrzebujesz kodera i dekodera, który otrzymasz od Base64Coder - kodera / dekodera Base64 typu open source w Javie . Potrzebny będzie plik Base64Coder.java .

Teraz, aby uzyskać dostęp do tej klasy zgodnie z wymaganiami, będziesz potrzebować klasy poniżej:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;

public class Base64 {

    public static void main(String args[]) throws IOException {
        /*
         * if (args.length != 2) {
         *     System.out.println(
         *         "Command line parameters: inputFileName outputFileName");
         *     System.exit(9);
         * } encodeFile(args[0], args[1]);
         */
        File sourceImage = new File("back3.png");
        File sourceImage64 = new File("back3.txt");
        File destImage = new File("back4.png");
        encodeFile(sourceImage, sourceImage64);
        decodeFile(sourceImage64, destImage);
    }

    private static void encodeFile(File inputFile, File outputFile) throws IOException {
        BufferedInputStream in = null;
        BufferedWriter out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(inputFile));
            out = new BufferedWriter(new FileWriter(outputFile));
            encodeStream(in, out);
            out.flush();
        }
        finally {
            if (in != null)
                in.close();
            if (out != null)
                out.close();
        }
    }

    private static void encodeStream(InputStream in, BufferedWriter out) throws IOException {
        int lineLength = 72;
        byte[] buf = new byte[lineLength / 4 * 3];
        while (true) {
            int len = in.read(buf);
            if (len <= 0)
                break;
            out.write(Base64Coder.encode(buf, 0, len));
            out.newLine();
        }
    }

    static String encodeArray(byte[] in) throws IOException {
        StringBuffer out = new StringBuffer();
        out.append(Base64Coder.encode(in, 0, in.length));
        return out.toString();
    }

    static byte[] decodeArray(String in) throws IOException {
        byte[] buf = Base64Coder.decodeLines(in);
        return buf;
    }

    private static void decodeFile(File inputFile, File outputFile) throws IOException {
        BufferedReader in = null;
        BufferedOutputStream out = null;
        try {
            in = new BufferedReader(new FileReader(inputFile));
            out = new BufferedOutputStream(new FileOutputStream(outputFile));
            decodeStream(in, out);
            out.flush();
        }
        finally {
            if (in != null)
                in.close();
            if (out != null)
                out.close();
        }
    }

    private static void decodeStream(BufferedReader in, OutputStream out) throws IOException {
        while (true) {
            String s = in.readLine();
            if (s == null)
                break;
            byte[] buf = Base64Coder.decodeLines(s);
            out.write(buf);
        }
    }
}

W Androidzie możesz przekonwertować mapę bitową na Base64 w celu przesłania jej na serwer lub usługę internetową.

Bitmap bmImage = //Data
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmImage.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] imageData = baos.toByteArray();
String encodedImage = Base64.encodeArray(imageData);

Ten „encodedImage” to tekstowa reprezentacja twojego obrazu. Możesz użyć tego do celów przesyłania lub do wyświetlania bezpośrednio na stronie HTML, jak poniżej ( odniesienie ):

<img alt="" src="data:image/png;base64,<?php echo $encodedImage; ?>" width="100px" />
<img alt="" src="data:image/png;base64,/9j/4AAQ...........1f/9k=" width="100px" />

Dokumentacja: http://dwij.co.in/java-base64-image-encoder

Web Developer w Pune
źródło
Ostatni link (dwij.co.in) jest zepsuty (404).
Peter Mortensen
9

Oto moje dwa centy ... Java 8 zawiera własną implementację Base64 . Znalazłem jednak jedną nieco niepokojącą różnicę. Aby to zilustrować, podam przykładowy kod:

Moje opakowanie kodeka:

public interface MyCodec
{
  static String apacheDecode(String encodedStr)
  {
    return new String(Base64.decodeBase64(encodedStr), Charset.forName("UTF-8"));
  }

  static String apacheEncode(String decodedStr)
  {
    byte[] decodedByteArr = decodedStr.getBytes(Charset.forName("UTF-8"));
    return Base64.encodeBase64String(decodedByteArr);
  }

  static String javaDecode(String encodedStr)
  {
    return new String(java.util.Base64.getDecoder().decode(encodedStr), Charset.forName("UTF-8"));
  }

  static String javaEncode(String decodedStr)
  {
    byte[] decodedByteArr = decodedStr.getBytes(Charset.forName("UTF-8"));
    return java.util.Base64.getEncoder().encodeToString(decodedByteArr);
  }
}

Klasa testowa:

public class CodecDemo
{
  public static void main(String[] args)
  {
    String decodedText = "Hello World!";

    String encodedApacheText = MyCodec.apacheEncode(decodedText);
    String encodedJavaText = MyCodec.javaEncode(decodedText);

    System.out.println("Apache encoded text: " + MyCodec.apacheEncode(encodedApacheText));
    System.out.println("Java encoded text: " + MyCodec.javaEncode(encodedJavaText));

    System.out.println("Encoded results equal: " + encodedApacheText.equals(encodedJavaText));

    System.out.println("Apache decode Java: " + MyCodec.apacheDecode(encodedJavaText));
    System.out.println("Java decode Java: " + MyCodec.javaDecode(encodedJavaText));

    System.out.println("Apache decode Apache: " + MyCodec.apacheDecode(encodedApacheText));
    System.out.println("Java decode Apache: " + MyCodec.javaDecode(encodedApacheText));
  }
}

WYNIK:

Apache encoded text: U0dWc2JHOGdWMjl5YkdRaA0K

Java encoded text: U0dWc2JHOGdWMjl5YkdRaA==
Encoded results equal: false
Apache decode Java: Hello World!
Java decode Java: Hello World!
Apache decode Apache: Hello World!
Exception in thread "main" java.lang.IllegalArgumentException: Illegal base64 character d
    at java.util.Base64$Decoder.decode0(Base64.java:714)
    at java.util.Base64$Decoder.decode(Base64.java:526)
    at java.util.Base64$Decoder.decode(Base64.java:549)

Zauważ, że tekst zakodowany w Apache zawiera dodatkowe znaki końca linii (białe spacje) na końcu. Dlatego też, aby mój kodek mógł uzyskać ten sam wynik niezależnie od implementacji Base64, musiałem wywołać trim()tekst zakodowany w Apache. W moim przypadku po prostu dodałem wyżej wymienione wywołanie metody do mojego kodeka w apacheDecode()następujący sposób:

return Base64.encodeBase64String(decodedByteArr).trim();

Po wprowadzeniu tej zmiany oczekiwałem od wyników:

Apache encoded text: U0dWc2JHOGdWMjl5YkdRaA==
Java encoded text: U0dWc2JHOGdWMjl5YkdRaA==
Encoded results equal: true
Apache decode Java: Hello World!
Java decode Java: Hello World!
Apache decode Apache: Hello World!
Java decode Apache: Hello World!

WNIOSEK : Jeśli chcesz przełączyć się z Apache Base64 na Java, musisz:

  1. Dekoduj zakodowany tekst za pomocą dekodera Apache.
  2. Zakoduj wynikowy (zwykły) tekst za pomocą Java.

Jeśli przełączysz się bez wykonania tych kroków, najprawdopodobniej wystąpią problemy. W ten sposób dokonałem tego odkrycia.

hfontanez
źródło
8

W systemie Android użyj statycznych metod klasy narzędzia android.util.Base64 . Dokumentacja, o której mowa, mówi, że klasa Base64 została dodana na poziomie API 8 ( Android 2.2 (Froyo)).

import android.util.Base64;

byte[] encodedBytes = Base64.encode("Test".getBytes());
Log.d("tag", "encodedBytes " + new String(encodedBytes));

byte[] decodedBytes = Base64.decode(encodedBytes);
Log.d("tag", "decodedBytes " + new String(decodedBytes));
Yojimbo
źródło
To najlepsza odpowiedź, jeśli programujesz dla Androida i nie możesz korzystać z Javy 8.
Craig Brown
6

Apache Commons ma niezłą implementację Base64. Możesz to zrobić po prostu:

// Encrypt data on your side using BASE64
byte[] bytesEncoded = Base64.encodeBase64(str .getBytes());
System.out.println("ecncoded value is " + new String(bytesEncoded));

// Decrypt data on other side, by processing encoded data
byte[] valueDecoded= Base64.decodeBase64(bytesEncoded );
System.out.println("Decoded value is " + new String(valueDecoded));

Więcej informacji na temat kodowania base64 można znaleźć w kodowaniu Base64 przy użyciu Java i JavaScript .

faisalbhagat
źródło
Zauważ, że zakłada to, że ciąg jest zakodowany w domyślnym zestawie znaków
Kirby
6

Jeśli używasz Spring Framework co najmniej w wersji 4.1, możesz użyć klasy org.springframework.util.Base64Utils :

byte[] raw = { 1, 2, 3 };
String encoded = Base64Utils.encodeToString(raw);
byte[] decoded = Base64Utils.decodeFromString(encoded);

Będzie delegować do Base64, Apache Commons Codec lub JAXB DatatypeConverter w Javie 8, w zależności od tego, co jest dostępne.

holmis83
źródło
4

Prosty przykład z Javą 8:

import java.util.Base64;

String str = "your string";
String encodedStr = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
z3d0
źródło
3

W Javie 7 kodowałem tę metodę

import javax.xml.bind.DatatypeConverter;

public static String toBase64(String data) {
    return DatatypeConverter.printBase64Binary(data.getBytes());
}
Daniel De León
źródło
Działa w Javie 7 i 8, ale nie w Javie 9. Gorzej, jeśli zbudujesz to w Javie 7 lub 8, to zbuduje się, a następnie otrzymasz wyjątek ClassDefNotFoundException w środowisku wykonawczym w Javie 9.
Stephen M - strajk -
1

Próbowałem z następującym fragmentem kodu. Działa dobrze. :-)

com.sun.org.apache.xml.internal.security.utils.Base64.encode("The string to encode goes here");
thh
źródło
0
public String convertImageToBase64(String filePath) {
    byte[] fileContent = new byte[0];
    String base64encoded = null;
    try {
        fileContent = FileUtils.readFileToByteArray(new File(filePath));
    } catch (IOException e) {
        log.error("Error reading file: {}", filePath);
    }
    try {
        base64encoded = Base64.getEncoder().encodeToString(fileContent);
    } catch (Exception e) {
        log.error("Error encoding the image to base64", e);
    }
    return base64encoded;
}
ghandour abdelkrim
źródło