Base64 кодирование в Java

Я использую Затмение. У меня есть следующая строка кода:

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

Eclipse помечает эту строку как ошибку. Я импортировал необходимые библиотеки:

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

Но опять же, оба они показаны как ошибки. Я нашел похожий пост здесь.

Я использовал Apache Commons в качестве решения, предложенного в том числе:

import org.apache.commons.*;

и импортировать файлы JAR, загруженные с: http://commons.apache.org/codec/

Но проблема все еще существует. Затмение все еще показывает ошибки, упомянутые ранее; пожалуйста, порекомендуйте.

19 ответов

Решение

Вам нужно изменить импорт вашего класса:

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

А затем измените свой класс, чтобы использовать класс Base64.

Вот пример кода:

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));

Тогда прочитайте, почему вы не должны использовать пакеты sun.*.


Обновление (16.12.2016)

Ты можешь сейчас java.util.Base64 с Java8. Во-первых, импортируйте его как обычно:

import java.util.Base64;

Затем используйте статические методы Base64 следующим образом:

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));

См. Javadocs для Base64 для получения дополнительной информации: https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html

Используйте класс Java 8 "никогда не поздно присоединиться к веселью": java.util.Base64

В Java 8 это можно сделать как

Base64.getEncoder().encodeToString(string.getBytes(StandardCharsets.UTF_8))

Вот короткий, автономный полный пример

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);
    }
}

дает вывод

old crow medicine show => b2xkIGNyb3cgbWVkaWNpbmUgc2hvdw==

Вы также можете конвертировать, используя base64 кодировку. Для этого вы можете использовать javax.xml.bind.DatatypeConverter#printBase64Binary метод

Например:

byte[] salt = new byte[] { 50, 111, 8, 53, 86, 35, -19, -47 };
System.out.println(DatatypeConverter.printBase64Binary(salt));

Google Guava - хороший выбор для кодирования и декодирования данных base64:

Конфигурация POM:

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

Образец кода:

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

Eclipse выдает сообщение об ошибке / предупреждение, потому что вы пытаетесь использовать внутренние классы, которые являются специфическими для поставщика JDK, а не являются частью общедоступного API. Jakarta Commons предоставляет собственную реализацию кодеков base64, которые, конечно, находятся в другом пакете. Удалите этот импорт и позвольте Eclipse импортировать соответствующую классу Commons для вас.

Для Java 6-7 лучшим вариантом является заимствование кода из хранилища Android. У него нет зависимостей.

https://github.com/android/platform_frameworks_base/blob/master/core/java/android/util/Base64.java

Вот мои два цента... Java 8 содержит свою собственную реализацию Base64, Однако я обнаружил одну слегка тревожную разницу. Для иллюстрации приведу пример кода:

Мой кодек обертка:

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);
  }
}

Тестовый класс:

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));
  }
}

ВЫХОД:

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)

Обратите внимание, что кодированный в Apache текст содержит дополнительные разрывы строк (пробелы) в конце. Поэтому для того, чтобы мой кодек давал один и тот же результат независимо от реализации Base64, мне пришлось вызвать trim() на Apache кодированный текст. В моем случае я просто добавил вышеупомянутый вызов метода в мой кодек apacheDecode() следующее:

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

После того, как это изменение было сделано, я ожидал, что результаты начнутся с:

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!

Возможно, кто-то мог бы прокомментировать, почему это так, но я нашел мой обходной путь приемлемым компромиссом.

Для конвертации вам необходим Encoder & Decoder, который вы получите по http://www.source-code.biz/base64coder/java/. Вам понадобится файл Base64Coder.java.

Теперь для доступа к этому классу согласно вашему требованию вам понадобится класс ниже:

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 &lt;= 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);
  }
 }
}

В Android вы можете конвертировать ваше растровое изображение в Base64 для загрузки на сервер / веб-сервис.

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

Этот "encodedImage" является текстовым представлением вашего изображения. Вы можете использовать это либо для загрузки, либо для воспроизведения непосредственно на HTML-странице, как показано ниже ( ссылка):

<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" />

Документация: http://dwij.co.in/java-base64-image-encoder

В Android используйте статические методы класса утилит android.util.Base64. В ссылочной документации сказано, что класс Base64 был добавлен на уровне API 8 (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));

Apache Commons имеет хорошую реализацию base64. Вы можете сделать это так же просто, как

// 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));

Вы можете найти более подробную информацию о кодировке base64 на http://faisalbhagat.blogspot.com/2014/06/base64-encoding-using-java-and.html

Если вы используете Spring Framework как минимум версии 4.1, вы можете использовать класс org.springframework.util.Base64Utils:

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

Он будет делегировать Java 8 Base64, Apache Commons Codec или JAXB DatatypeConverter, в зависимости от того, что доступно.

В Java 7 я закодировал этот метод

import javax.xml.bind.DatatypeConverter;

public static String toBase64(String data) {
    return DatatypeConverter.printBase64Binary(data.getBytes());
}

Простой пример с Java 8:

import java.util.Base64;

String str = "your string";
String encodedStr = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));

Если вы используете более раннюю версию Java, чем 8, но уже используете AWS SDK для Java, вы можете использовать com.amazonaws.util.Base64.

Я попытался с помощью следующего фрагмента кода. Это сработало хорошо.:-)

com.sun.org.apache.xml.internal.security.utils.Base64.encode("The string to encode goes here");
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;
}

GZIP + Base64

Длина строки в формате больше исходной: 133%в среднем. Поэтому имеет смысл сначала сжать его с помощью GZIP, а затем кодировать в Base64. Это дает сокращение до 77%для строк длиной более 200 символов. Пример:

      public static void main(String[] args) throws IOException {
    byte[] original = randomString(100).getBytes(StandardCharsets.UTF_8);

    byte[] base64 = encodeToBase64(original);
    byte[] gzipToBase64 = encodeToBase64(encodeToGZIP(original));

    byte[] fromBase64 = decodeFromBase64(base64);
    byte[] fromBase64Gzip = decodeFromGZIP(decodeFromBase64(gzipToBase64));

    // test
    System.out.println("Original: " + original.length + " bytes, 100%");
    System.out.println("Base64: " + base64.length + " bytes, "
            + (base64.length * 100 / original.length) + "%");
    System.out.println("GZIP+Base64: " + gzipToBase64.length + " bytes, "
            + (gzipToBase64.length * 100 / original.length) + "%");

    //Original: 3700 bytes, 100%
    //Base64: 4936 bytes, 133%
    //GZIP+Base64: 2868 bytes, 77%

    System.out.println(Arrays.equals(original, fromBase64)); // true
    System.out.println(Arrays.equals(original, fromBase64Gzip)); // true
}
      public static byte[] decodeFromBase64(byte[] arr) {
    return Base64.getDecoder().decode(arr);
}

public static byte[] encodeToBase64(byte[] arr) {
    return Base64.getEncoder().encode(arr);
}
      public static byte[] decodeFromGZIP(byte[] arr) throws IOException {
    ByteArrayInputStream bais = new ByteArrayInputStream(arr);
    GZIPInputStream gzip = new GZIPInputStream(bais);
    return gzip.readAllBytes();
}

public static byte[] encodeToGZIP(byte[] arr) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    GZIPOutputStream gzip = new GZIPOutputStream(baos);
    gzip.write(arr);
    gzip.finish();
    return baos.toByteArray();
}
      public static String randomString(int count) {
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < count; i++) {
        str.append(" ").append(UUID.randomUUID().toString());
    }
    return str.toString();
}

См. Также: Как получить файл JAR для класса sun.misc.BASE64Encoder?

добавьте эту библиотеку в зависимости от уровня вашего приложения

реализация 'org.apache.commons:commons-collections4:4.4'

Другие вопросы по тегам