【问题标题】:Encoding as Base64 in Java在 Java 中编码为 Base64
【发布时间】:2012-10-18 01:21:47
【问题描述】:

我需要在 Java 中使用 Base64 编码对一些数据进行编码。我怎么做?提供 Base64 编码器的类叫什么名字?


我尝试使用sun.misc.BASE64Encoder 类,但没有成功。我有以下 Java 7 代码行:

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

我正在使用 Eclipse。 Eclipse 将此行标记为错误。我导入了所需的库:

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

但同样,它们都显示为错误。我找到了a similar post here

我使用 Apache Commons 作为建议的解决方案,包括:

import org.apache.commons.*;

并导入从以下位置下载的 JAR 文件:http://commons.apache.org/codec/

但问题依然存在。 Eclipse 仍然显示前面提到的错误。我该怎么办?

【问题讨论】:

标签: java base64 decode encode


【解决方案1】:

您需要更改类的导入:

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

然后阅读why you shouldn't use sun.* packages


更新 (2016-12-16)

您现在可以在 Java 8 中使用 java.util.Base64。首先,像往常一样导入它:

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

如果你直接想对字符串进行编码并得到编码后的字符串,你可以这样:

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

请参阅Java documentation for Base64 了解更多信息。

【讨论】:

  • 我需要下载任何外部软件包才能使用吗?如果是,是哪个?
  • 不,你不需要下载任何东西 afaik
  • org.apache.commons.codec.binary.Base64 看起来不像默认库。我想你必须为此包括 apache commons。对吗?
  • @Frank 一次解码字节会引发 OutOfMemory 错误。任何想法都可以在缓冲区中处理它
  • commons.apache.org/proper/commons-codec/dependency-info.html 例如毕业compile 'commons-codec:commons-codec:1.15'
【解决方案2】:

使用 Java 8 永远不会太晚加入的有趣类:java.util.Base64

new String(Base64.getEncoder().encode(bytes));

【讨论】:

  • 虽然是一条微不足道的评论,但请注意,如果您使用该评论,则与旧版本的 Java 不兼容,后者(至少在此时)可能更为普遍。
  • 我也会选择Java 8的类是可能的。我目前正在研究一个从我们的 spring 项目中删除 apache commons 库的类。大多数东西都可以很容易地用 Spring 库或 jdk 中的方法替换。
  • 首选返回String的函数类型:Base64.getEncoder().encodeToString("blah".getBytes())
【解决方案3】:

在 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==

【讨论】:

  • 为什么Java标准库中没有Charset常量,哦,为什么?!
  • 好问题,卢卡斯!实际上,有。我忘了! java.nio.charset.StandardCharsets。我会编辑我的答案。见stackoverflow.com/questions/1684040/…
【解决方案4】:

您还可以使用 Base64 编码进行转换。为此,您可以使用javax.xml.bind.DatatypeConverter#printBase64Binary 方法。

例如:

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

【讨论】:

  • 虽然这可行,但文档特别指出:DatatypeConverterInterface 仅供 JAXB 提供程序使用。
  • 我认为@gebirgsbaerbel 是错误的,printX() 和 parseX() 方法可以被任何人使用,唯一适用于 JAXB 的是 setDatatypeConverter() 方法(然后必须调用它对于 JAXB 提供程序)。
  • 最终,Java 8 中的 Base64 类将成为的发展方向。但如果您同时必须以 Java 7 为目标,那么这个解决方案很好,因为它不依赖外部库。
  • 这在 Java 9 下不起作用。更糟糕的是,使用 javax.xml.bind.* 为 Java 7 编译的代码将在 Java 9 下运行时失败。
【解决方案5】:

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

【讨论】:

    【解决方案6】:

    Eclipse 会给您一个错误/警告,因为您正在尝试使用特定于 JDK 供应商的内部类,而不是公共 API 的一部分。 Jakarta Commons 提供了自己的 base64 编解码器实现,当然它们位于不同的包中。删除这些导入并让 Eclipse 为您导入正确的 Commons 类。

    【讨论】:

    【解决方案7】:

    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 实现如何都能产生相同的结果,我必须在 Apache 编码文本上调用 trim()。就我而言,我只是将上述方法调用添加到我的编解码器的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!
    

    结论:如果您想从 Apache Base64 切换到 Java,您必须:

    1. 使用 Apache 解码器解码编码文本。
    2. 使用 Java 对生成的(纯)文本进行编码。

    如果您在不执行这些步骤的情况下进行切换,您很可能会遇到问题。这就是我做出这个发现的原因。

    【讨论】:

    • 确实很有趣。当非预期的代码开始失败时,这些小事可能会给你带来沉重的打击
    • @aran 我发现这是错误的方式。我必须在业务应用程序中实现,因为这个问题,它在我面前爆炸了。幸运的是,1)我在一个单独的分支上工作,并且 2)我有很好的诊断技能(尤其是当我的背靠墙 LOL 时)。我来这里是为了学习如何做到这一点,并最终倾向于我永远不会落入一个完全准确的答案,即使它被选为答案和/或有数百个赞成票。魔鬼在细节上。
    【解决方案8】:

    对于Java 6-7,最好的选择是从 Android 存储库中借用代码。它没有依赖关系。

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

    【讨论】:

      【解决方案9】:

      要转换它,您需要一个编码器和解码器,您可以从 Base64Coder - an open-source Base64 encoder/decoder in 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 <= 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 页面中,如下所示 (reference):

      <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

      【讨论】:

      • 最后一个链接 (dwij.co.in) 已损坏 (404)。
      【解决方案10】:

      在 Android 上,使用 android.util.Base64 实用程序类的静态方法。参考文档说 Base64 类是在 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));
      

      【讨论】:

      • 如果您正在为 Android 开发并且不能使用 Java 8,这是最好的答案。
      【解决方案11】:

      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 encoding using Java and JavaScript 找到有关 base64 编码的更多详细信息。

      【讨论】:

      • 请注意,这假定字符串以默认字符集编码
      【解决方案12】:

      如果你使用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,具体取决于可用的内容。

      【讨论】:

        【解决方案13】:

        Java 8 的简单示例:

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

        【讨论】:

          【解决方案14】:

          在 Java 7 中我编写了这个方法

          import javax.xml.bind.DatatypeConverter;
          
          public static String toBase64(String data) {
              return DatatypeConverter.printBase64Binary(data.getBytes());
          }
          

          【讨论】:

          • 在 Java 7 和 8 下工作,但在 Java 9 下不工作。更糟糕的是,如果你在 Java 7 或 8 下构建它,它会构建,然后你会在 Java 9 下运行时获得 ClassDefNotFoundException。跨度>
          【解决方案15】:

          如果您坚持使用早于 8 的 Java 版本但已经在使用 AWS SDK for Java,则可以使用 com.amazonaws.util.Base64

          【讨论】:

            【解决方案16】:

            我尝试使用以下代码 sn-p。它运作良好。 :-)

            com.sun.org.apache.xml.internal.security.utils.Base64.encode("The string to encode goes here");
            

            【讨论】:

              【解决方案17】:
              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;
              }
              

              【讨论】:

                【解决方案18】:

                将此库添加到您的应用级依赖项中

                实现'org.apache.commons:commons-collections4:4.4'

                【讨论】:

                  【解决方案19】:

                  GZIP + Base64

                  Base64 格式的字符串长度平均大于原始字符串:133%。所以先用GZIP压缩,再编码成Base64是有意义的。对于超过 200 个字符或更多字符的字符串,它最多可减少 77%。示例:

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

                  另见:How to get the JAR file for sun.misc.BASE64Encoder class?

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-07-21
                    • 2016-04-04
                    • 2011-05-10
                    • 2011-08-13
                    • 1970-01-01
                    相关资源
                    最近更新 更多