- 什么是二进制数据? (在 Java 中的体现)
- 什么是 Base64?
- Java 8 及更高版本 (推荐):使用
java.util.Base64 - Java 8 之前版本:使用第三方库 (如 Apache Commons Codec)
- 完整代码示例
- 最佳实践和注意事项
什么是二进制数据? (在 Java 中的体现)
在 Java 中,"二进制数据" 通常不是指一个简单的 byte 原始类型,而是指一个字节数组 (byte[]),无论是图片、音频、视频、压缩文件,还是任何需要在网络上传输的非文本数据,在内存中都是以 byte[] 的形式存在的。

byte[]: 这是最核心的表示方式,从一个文件中读取的内容就是一个byte[]。InputStream/OutputStream: 当处理大文件时,我们不会一次性将所有数据读入内存,而是使用流式处理。InputStream是二进制数据的来源,OutputStream是二进制数据的去向。ByteBuffer: 在 NIO (New I/O) 中,ByteBuffer提供了更灵活的方式来处理二进制数据。
什么是 Base64?
Base64 是一种用 64 个可打印字符来表示任意二进制数据的方法,它常用于:
- 在文本协议中传输二进制数据:因为很多系统(如 HTTP、Email)最初只设计来处理文本(ASCII),直接传输二进制数据(如
0x00或0xFF)可能会导致问题,Base64 将二进制数据转换成纯文本,可以安全地嵌入到这些协议中。 - 简单的数据编码:它不是加密,而是一种编码,所以任何人都可以解码,它只是让数据变得“可打印”。
工作原理简述:
- 将 3 个字节 (24 位) 的二进制数据作为一组。
- 将这 24 位重新划分为 4 组,每组 6 位。
- 将这 4 个 6 位的值分别作为索引,去查一个包含 64 个字符的表(A-Z, a-z, 0-9, '+', '/')。
- 得到 4 个 Base64 字符。
- 如果输入的字节数不是 3 的倍数,会用 进行填充。
Java 8 及更高版本 (推荐)
从 Java 8 开始,标准库中正式引入了 java.util.Base64 类,它提供了简单、高效且标准的方式来处理 Base64 编码和解码。这是目前推荐使用的方式。
java.util.Base64 类的核心方法
这个类提供了 getEncoder(), getDecoder(), getMimeEncoder(), getMimeDecoder() 等静态方法来获取不同的编解码器。

Base64.getEncoder(): 标准的 Base64 编码器。Base64.getDecoder(): 标准的 Base64 解码器。Base64.getMimeEncoder(): MIME 友好的 Base64 编码器,它会在每 76 个字符后插入一个换行符\n,这符合 MIME (Multipurpose Internet Mail Extensions) 标准,适合在 Email 等场景使用。Base64.getMimeDecoder(): MIME 友好的 Base64 解码器。
核心方法
- 编码:
byte[] encode(byte[] src): 编码字节数组。String encodeToString(byte[] src): 编码字节数组并直接返回一个字符串。OutputStream wrap(OutputStream os): 返回一个OutputStream,写入其中的任何数据都会被自动 Base64 编码。
- 解码:
byte[] decode(byte[] src): 解码 Base64 编码的字节数组。byte[] decode(String src): 解码 Base64 编码的字符串。InputStream wrap(InputStream is): 返回一个InputStream,从中读取的任何数据都会被自动 Base64 解码。
Java 8 之前版本
如果你在使用 Java 7 或更早的版本,标准库中没有 Base64 支持,这时,最常用、最可靠的选择是 Apache Commons Codec 库。
如何添加依赖 (Maven)
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version> <!-- 使用最新的稳定版本 -->
</dependency>
Apache Commons Codec 的核心类
核心类是 org.apache.commons.codec.binary.Base64。
- 编码:
static byte[] encodeBase64(byte[] binaryData): 编码字节数组。static String encodeBase64String(byte[] binaryData): 编码字节数组并返回字符串。
- 解码:
static byte[] decodeBase64(byte[] base64Data): 解码 Base64 字节数组。static byte[] decodeBase64(String base64String): 解码 Base64 字符串。
完整代码示例
下面我们通过一个完整的 Java 8 示例来演示所有核心操作。
示例:文件 <-> 字节数组 <-> Base64 字符串
这个例子展示了如何读取一个图片文件,将其编码为 Base64 字符串,然后再将字符串解码并写回到一个新的文件中。

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
public class BinaryBase64Example {
public static void main(String[] args) {
// 假设我们有一个名为 "sample.png" 的图片文件在项目根目录下
String originalFilePath = "sample.png";
String encodedFilePath = "encoded.txt";
String decodedFilePath = "decoded_copy.png";
try {
// 1. 从文件读取二进制数据 (字节数组)
byte[] fileBytes = readAllBytesOrExit(originalFilePath);
System.out.println("原始文件大小: " + fileBytes.length + " 字节");
// 2. 将字节数组编码为 Base64 字符串
// 使用标准编码器
Base64.Encoder encoder = Base64.getEncoder();
String base64String = encoder.encodeToString(fileBytes);
System.out.println("Base64 编码后的字符串 (前 50 个字符): " + base64String.substring(0, 50) + "...");
System.out.println("Base64 字符串长度: " + base64String.length());
// 将 Base64 字符串保存到文件中
Files.write(Paths.get(encodedFilePath), base64String.getBytes());
System.out.println("Base64 字符串已保存到: " + encodedFilePath);
// 3. 从文件读取 Base64 字符串
String base64FromFile = new String(Files.readAllBytes(Paths.get(encodedFilePath)));
// 4. 将 Base64 字符串解码为字节数组
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodedBytes = decoder.decode(base64FromFile);
System.out.println("解码后的字节数组大小: " + decodedBytes.length + " 字节");
// 5. 将解码后的字节数组写回到新文件
Files.write(Paths.get(decodedFilePath), decodedBytes);
System.out.println("解码后的文件已保存到: " + decodedFilePath);
System.out.println("操作完成!请检查 'decoded_copy.png' 是否与 'sample.png' 一致。");
} catch (IOException e) {
System.err.println("处理文件时发生错误: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 一个简单的辅助方法,用于读取文件的所有字节。
* 如果文件不存在,则打印错误信息并退出程序。
*/
private static byte[] readAllBytesOrExit(String filePath) throws IOException {
Path path = Paths.get(filePath);
if (!Files.exists(path)) {
System.err.println("错误: 文件 '" + filePath + "' 不存在!");
System.exit(1);
}
return Files.readAllBytes(path);
}
}
示例:使用流处理大文件
对于非常大的文件,将整个文件读入内存可能会导致 OutOfMemoryError,这时,使用 Base64.getEncoder().wrap() 和 Base64.getDecoder().wrap() 进行流式处理是最佳选择。
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
public class StreamBase64Example {
public static void main(String[] args) {
String largeFilePath = "large_file.zip"; // 假设这是一个大文件
String encodedStreamFilePath = "large_encoded.txt";
String decodedStreamFilePath = "large_decoded.zip";
try {
// 编码:文件 -> InputStream -> Base64 OutputStream -> 文件
encodeFile(largeFilePath, encodedStreamFilePath);
System.out.println("大文件流式编码完成。");
// 解码:Base64 文件 -> InputStream -> Base64 InputStream -> 文件
decodeFile(encodedStreamFilePath, decodedStreamFilePath);
System.out.println("大文件流式解码完成。");
} catch (IOException e) {
System.err.println("流处理时发生错误: " + e.getMessage());
e.printStackTrace();
}
}
private static void encodeFile(String sourcePath, String targetPath) throws IOException {
try (InputStream is = Files.newInputStream(Paths.get(sourcePath));
OutputStream os = Files.newOutputStream(Paths.get(targetPath))) {
// 创建一个 Base64 编码输出流,所有写入 os 的数据都会被自动编码
Base64.Encoder encoder = Base64.getEncoder();
OutputStream encodedOs = encoder.wrap(os);
// 使用缓冲流提高性能
byte[] buffer = new byte[8192]; // 8KB 缓冲区
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
encodedOs.write(buffer, 0, bytesRead);
}
// encodedOs.close() 会在 try-with-resources 中自动调用
}
}
private static void decodeFile(String sourcePath, String targetPath) throws IOException {
try (InputStream is = Files.newInputStream(Paths.get(sourcePath));
OutputStream os = Files.newOutputStream(Paths.get(targetPath))) {
// 创建一个 Base64 解码输入流,所有从 is 读取的数据都会被自动解码
Base64.Decoder decoder = Base64.getDecoder();
InputStream decodedIs = decoder.wrap(is);
// 使用缓冲流提高性能
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = decodedIs.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
// decodedIs.close() 会在 try-with-resources 中自动调用
}
}
}
最佳实践和注意事项
-
首选 Java 8+
java.util.Base64:如果你的项目使用 Java 8 或更高版本,请务必使用标准库,它不需要引入外部依赖,并且性能和可靠性都经过了充分验证。 -
注意数据增长:Base64 编码会使数据大小增加约 33%,因为每 3 个字节(24位)会变成 4 个字符,这在处理大文件时需要考虑存储和网络带宽成本。
-
区分编码和解码:
- 编码:
byte[](二进制) ->String(Base64 文本) - 解码:
String(Base64 文本) ->byte[](二进制)
- 编码:
-
MIME vs 标准:
- 如果你的 Base64 数据需要嵌入到 Email (MIME 消息) 或需要符合某些 Web 标准,请使用
getMimeEncoder()和getMimeDecoder()。 - 如果只是简单的数据交换,使用标准的
getEncoder()和getDecoder()即可。
- 如果你的 Base64 数据需要嵌入到 Email (MIME 消息) 或需要符合某些 Web 标准,请使用
-
安全性:再次强调,Base64 是编码,不是加密,它不能保护数据的机密性,如果数据是敏感的,必须先进行加密(如使用 AES),然后再对加密后的密文进行 Base64 编码。
-
处理异常:在进行 Base64 解码时,如果输入的字符串格式不正确(包含非法字符或填充不正确),
decode方法会抛出IllegalArgumentException,务必做好异常处理。
