دیکد کردن Base64 در Java چیزی است که هر چند روز یکبار به آن نیاز پیدا میکنم — خواندن secret ها از متغیرهای محیطی Kubernetes، پردازش payload های باینری از REST API ها، بررسی توکنهای JWT در طول debugging. کلاس داخلی java.util.Base64 جاوا (از JDK 8) سه نوع دیکودر ارائه میدهد: getDecoder() برای Base64 استاندارد، getUrlDecoder() برای ورودی URL-safe، و getMimeDecoder() برای دادههای شکستهشده در خط مانند پیوستهای ایمیل. برای بررسی سریع بدون نوشتن کد، دیکودر Base64 ToolDeck آن را فوری در مرورگر شما انجام میدهد. این راهنما برای Java 8+ است و هر سه دیکودر، استریمینگ با wrap(InputStream)، استخراج payload JWT، دیکد کردن فایلها و پاسخهای API، Apache Commons Codec بهعنوان جایگزین، و چهار اشتباه رایجی که خروجی خراب در محیط production تولید میکنند را پوشش میدهد.
- ✓Base64.getDecoder().decode(s) روش استاندارد است — در java.util.Base64 از JDK 8 به بعد وجود دارد و به هیچ وابستگیای نیاز ندارد.
- ✓برای توکنهای JWT و payload های OAuth از getUrlDecoder() استفاده کنید — آنها از الفبای - و _ استفاده میکنند، نه + و /.
- ✓getMimeDecoder() شکست خط و فاصله را نادیده میگیرد و برای پیوستهای ایمیل و گواهینامههای PEM گزینه مناسبی است.
- ✓decoder.wrap(InputStream) برای فایلهای بزرگ بدون بارگذاری همه چیز در حافظه، دیکد لایو انجام میدهد.
- ✓دیکودر پایه سختگیرانه است — newline های انتهایی، فاصلهها، یا کاراکترهای الفبای اشتباه فوراً IllegalArgumentException پرتاب میکنند.
دیکد کردن Base64 چیست؟
کدگذاری Base64 دادههای باینری را به یک نمایش ASCII 64 کاراکتری تبدیل میکند تا بتوانند از طریق کانالهای متنی — فیلدهای JSON، هدرهای HTTP، اسناد XML، بدنه ایمیل — بهسلامت منتقل شوند. دیکد کردن این فرایند را معکوس میکند: هر ۴ کاراکتر Base64 به ۳ بایت اصلی بازمیگردند. پدینگ = در انتها نشان میدهد چند بایت برای پر کردن گروه آخر اضافه شده است. Base64 رمزگذاری نیست — هر کسی میتواند آن را معکوس کند. هدف آن سلامت انتقال است، نه محرمانگی.
سناریوهای رایج دیکد کردن در Java: استخراج مقادیر پیکربندی که بهصورت متغیر محیطی Base64 تزریق شدهاند، باز کردن بستهبندی محتوای باینری فایل از پاسخهای cloud API، خواندن گواهینامههای PEM-encoded، و بررسی payload توکنهای JWT در طول debugging.
db-prod.us-east-1.amazonaws.com:5432
ZGItcHJvZC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbTo1NDMy
Base64.getDecoder().decode() — روش استاندارد دیکد کردن
کلاس java.util.Base64 در JDK 8 اضافه شد و جایگزین sun.misc.BASE64Decoder قدیمی که همه به آن متکی بودند شد. هیچ وابستگی خارجی لازم نیست — فقط import java.util.Base64 کرده و Base64.getDecoder().decode() را فراخوانی کنید. این متد یا یک String یا یک byte[] میپذیرد و یک byte[] از دادههای دیکدشده برمیگرداند.
یک مثال ساده
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class DecodeCredential {
public static void main(String[] args) {
// Kubernetes secret value, Base64-encoded
String encoded = "ZGItcHJvZC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbTo1NDMy";
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String connectionString = new String(decodedBytes, StandardCharsets.UTF_8);
System.out.println(connectionString);
// db-prod.us-east-1.amazonaws.com:5432
}
}همیشه هنگام ساخت String مقدار StandardCharsets.UTF_8 را مشخص کنید. سازنده بدون آرگومان new String(bytes) از کدگذاری پیشفرض پلتفرم استفاده میکند که بین سیستمها متفاوت است. روی یک سرور Windows با Cp1252 بهعنوان پیشفرض، کاراکترهای UTF-8 چندبایتی بهآرامی خراب میشوند.
تست رفتوبرگشت
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class RoundTrip {
public static void main(String[] args) {
String original = "redis://cache-prod.internal:6379/session-store";
String encoded = Base64.getEncoder().encodeToString(
original.getBytes(StandardCharsets.UTF_8)
);
System.out.println(encoded);
// cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ==
byte[] decoded = Base64.getDecoder().decode(encoded);
String recovered = new String(decoded, StandardCharsets.UTF_8);
System.out.println(recovered.equals(original)); // true
}
}دیکد مستقیم به بافر
overload با سه آرگومان decode(byte[] src, byte[] dst) مستقیماً به یک بافر مقصد مینویسد و تعداد بایتهای نوشتهشده را برمیگرداند. این کار یک allocation اضافی در مسیرهای پر ترافیک را حذف میکند:
import java.util.Base64;
public class DecodeToBuffer {
public static void main(String[] args) {
byte[] src = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=".getBytes();
byte[] dst = new byte[1024]; // pre-allocated
int len = Base64.getDecoder().decode(src, dst);
String result = new String(dst, 0, len);
System.out.println(result);
// {"host":"10.0.1.50","port":8443}
}
}decode() یک IllegalArgumentException پرتاب میکند اگر ورودی شامل کاراکترهایی خارج از الفبای Base64 (از جمله شکست خط و فاصله) باشد. اگر ورودی شما ممکن است فاصله داشته باشد، به getMimeDecoder() سوئیچ کنید یا قبل از دیکد با encoded.strip() آن را پاکسازی کنید.دیکد کردن Base64 با انواع غیراستاندارد و اشیاء سفارشی
byte[] خام از decode() اغلب باید به چیز خاصتری تبدیل شود: یک UUID، یک شیء جاوای سریالیز شده، یک پیام protobuf، یا یک timestamp. دیکودر همیشه بایت برمیگرداند — تبدیل به انواع domain مسئولیت شماست.
Base64 به UUID
import java.util.Base64;
import java.nio.ByteBuffer;
import java.util.UUID;
public class DecodeUUID {
public static UUID fromBase64(String encoded) {
byte[] bytes = Base64.getUrlDecoder().decode(encoded);
ByteBuffer bb = ByteBuffer.wrap(bytes);
return new UUID(bb.getLong(), bb.getLong());
}
public static void main(String[] args) {
// Compact Base64-encoded UUID from an API response
String encoded = "f47ac10b-58cc-4372-a567-0e02b2c3d479";
UUID original = UUID.fromString(encoded);
// Encode to Base64 (compact form — 22 chars vs 36)
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(original.getMostSignificantBits());
bb.putLong(original.getLeastSignificantBits());
String compact = Base64.getUrlEncoder().withoutPadding()
.encodeToString(bb.array());
System.out.println(compact); // 9HrBC1jMQ3KlZw4CssPUeQ
// Decode back
UUID recovered = fromBase64(compact);
System.out.println(recovered); // f47ac10b-58cc-4372-a567-0e02b2c3d479
}
}Base64 به شیء JSON دسریالیزشده با Jackson
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Instant;
public class DecodeJsonPayload {
record DeployEvent(String service, String region, Instant deployedAt, int replicas) {}
public static void main(String[] args) throws Exception {
// Base64-encoded JSON payload from a message queue
String encoded = "eyJzZXJ2aWNlIjoicGF5bWVudC1nYXRld2F5Iiwi"
+ "cmVnaW9uIjoiZXUtd2VzdC0xIiwiZGVwbG95ZWRBdCI6"
+ "IjIwMjYtMDMtMTVUMTQ6MzA6MDBaIiwicmVwbGljYXMiOjR9";
byte[] jsonBytes = Base64.getDecoder().decode(encoded);
String json = new String(jsonBytes, StandardCharsets.UTF_8);
System.out.println(json);
// {"service":"payment-gateway","region":"eu-west-1",
// "deployedAt":"2026-03-15T14:30:00Z","replicas":4}
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules(); // picks up JavaTimeModule
DeployEvent event = mapper.readValue(jsonBytes, DeployEvent.class);
System.out.println(event.service()); // payment-gateway
System.out.println(event.deployedAt()); // 2026-03-15T14:30:00Z
}
}ObjectInputStream برای دسریالیز کردن دادههای Base64 غیرمعتمد استفاده نکنید. حملات deserialization جاوا کاملاً مستند شدهاند — اگر محتوای کدگذاریشده از یک منبع خارجی میآید، بهجای استفاده از سریالیزاسیون native جاوا، آن را بهصورت JSON یا protobuf تجزیه کنید.مرجع متدهای Base64.Decoder
تمام متدها به java.util.Base64 و کلاس داخلی آن Base64.Decoder تعلق دارند. سه متد factory روی Base64 نمونههای دیکودر مختلفی برمیگردانند؛ متدهای decode() و wrap() روی نمونه Decoder هستند.
getMimeDecoder() — دیکد کردن Base64 شکستهشده در خط و MIME
دیکودر پایه هر چیزی خارج از الفبای Base64 را رد میکند — و این شامل شکستهای خط \r\n میشود که محتوای MIME-encoded همیشه دارد. پیوستهای ایمیل، گواهینامههای PEM، و برخی پاسخهای قدیمی API خروجی Base64 را در ۷۶ کاراکتر در هر خط میشکنند. getMimeDecoder() جداکنندههای خط و هر کاراکتری که در الفبای Base64 نیست را بدون مشکل نادیده میگیرد، بنابراین این حالت را out of the box مدیریت میکند.
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class MimeDecode {
public static void main(String[] args) {
// PEM certificate body — line-wrapped at 76 characters
String pemBody = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t\r\n"
+ "TUlJQm96Q0NBVWlnQXdJQkFnSUpBSXBhVDJU\r\n"
+ "aVFvZU1BMEdDU3FHU0liM0RRRU==";
// getDecoder() would throw IllegalArgumentException here
byte[] decoded = Base64.getMimeDecoder().decode(pemBody);
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// -----BEGIN CERTIFICATE-----
// MIIBozCCAUigAwIBAgIJAIpaT2T...
}
}getMimeDecoder() منعطف است: بهجای پرتاب exception از روی کاراکترهای نامعتبر عبور میکند. این برای دادههای MIME شناختهشده مناسب است، اما میتواند خرابی را در ورودی دلخواه بهآرامی ببلعد. وقتی میخواهید اعتبارسنجی دقیق داشته باشید از getDecoder() استفاده کنید.دیکد کردن Base64 از فایل و پاسخ API
خواندن یک فایل Base64-encoded از دیسک
فایلهای باینری (تصاویر، گواهینامهها، blob های رمزگذاریشده) گاهی بهصورت متن Base64 روی دیسک ذخیره میشوند. فایل را بخوانید، دیکد کنید، خروجی باینری را بنویسید:
import java.util.Base64;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class DecodeFile {
public static void main(String[] args) {
Path inputPath = Path.of("tls-cert.pem.b64");
Path outputPath = Path.of("tls-cert.pem");
try {
String encoded = Files.readString(inputPath).strip();
byte[] decoded = Base64.getMimeDecoder().decode(encoded);
Files.write(outputPath, decoded);
System.out.printf("Decoded %d bytes → %s%n", decoded.length, outputPath);
} catch (IOException e) {
System.err.println("File error: " + e.getMessage());
} catch (IllegalArgumentException e) {
System.err.println("Invalid Base64: " + e.getMessage());
}
}
}دیکد کردن یک فیلد Base64 از پاسخ HTTP API
API های ابری (AWS KMS، GitHub Contents، Vault) اغلب دادههای باینری را بهصورت رشتههای Base64 داخل JSON برمیگردانند. ابتدا JSON را parse کنید، سپس فیلد هدف را دیکد کنید:
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DecodeApiResponse {
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/secrets/db-password"))
.header("Authorization", "Bearer sk-prod-9f8e7d6c")
.build();
try {
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
System.err.printf("Unexpected status: %d%n", response.statusCode());
return;
}
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(response.body());
// API returns: {"name":"db-password","value":"cG9zdGdyZXM6eGs5...","version":3}
String encodedValue = root.get("value").asText();
byte[] decoded = Base64.getDecoder().decode(encodedValue);
String secret = new String(decoded, StandardCharsets.UTF_8);
System.out.println("Secret: " + secret);
// Secret: postgres:xk9mP2qR@db-prod:5432/orders
} catch (Exception e) {
System.err.println("Failed to fetch secret: " + e.getMessage());
}
}
}IllegalArgumentException جدا از خطاهای شبکه قرار دهید. ترکیب کردن exception های I/O با خرابیهای دیکد کردن debugging را سختتر میکند — میخواهید سریع بفهمید مشکل از سمت API بوده یا شبکه.دیکد کردن Base64 از خط فرمان
همیشه به یک برنامه جاوا نیاز ندارید. هر سیستم Linux و macOS دستور base64 دارد، و JDK 9+ با jshell برای one-liner های تعاملی جاوا ارائه میشود. برای بازرسی سریع در طول debugging، اینها از کامپایل یک کلاس سریعترند.
# Decode a Base64 string (Linux / macOS)
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode
# {"host":"10.0.1.50","port":8443}
# Decode and pretty-print with jq
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode | jq .
# {
# "host": "10.0.1.50",
# "port": 8443
# }
# Quick decode with jshell (JDK 9+)
echo 'System.out.println(new String(java.util.Base64.getDecoder().decode("c2VydmVyLWNvbmZpZw==")))' | jshell -
# server-config
# macOS uses -D instead of --decode
echo "c2VydmVyLWNvbmZpZw==" | base64 -Dبرای paste کردن مستقیم رشتههای encoded در مرورگر، دیکودر Base64 ToolDeck هم نوع استاندارد و هم URL-safe را بدون هیچ راهاندازی مدیریت میکند.
جایگزین پرکارایی: Apache Commons Codec
java.util.Base64 داخلی جاوا از قبل بهینهسازی شده است — JDK 11+ از intrinsics روی x86 برای کدگذاری و دیکد کردن استفاده میکند. برای بیشتر برنامهها، دلیلی برای رفتن سراغ یک کتابخانه شخص ثالث وجود ندارد. با این حال، Apache Commons Codec در codebases قدیمی محبوب است و Base64InputStream را برای دیکد استریمینگ با مدیریت خودکار whitespace ارائه میدهد.
<!-- pom.xml -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.17.0</version>
</dependency>import org.apache.commons.codec.binary.Base64;
public class CommonsCodecDecode {
public static void main(String[] args) {
// Commons Codec is more lenient — handles whitespace and line breaks
String encoded = "eyJob3N0IjoiMTAuMC4xLjUw\nIiwicG9ydCI6ODQ0M30=";
byte[] decoded = Base64.decodeBase64(encoded);
System.out.println(new String(decoded));
// {"host":"10.0.1.50","port":8443}
}
}مزیت اصلی Commons Codec نسبت به API داخلی، انعطاف آن با whitespace بهطور پیشفرض و کلاس Base64InputStream آن است که از decoder.wrap() جاوا قدیمیتر است. اگر روی Java 8+ هستید، API داخلی همه چیزی را که Commons Codec انجام میدهد پوشش میدهد. تنها زمانی سراغ Commons Codec میروم که پروژه از قبل به آن وابسته است.
استریمینگ فایلهای بزرگ Base64 با decoder.wrap()
بارگذاری یک فایل Base64 با حجم ۲۰۰ مگابایت با Files.readString() و سپس فراخوانی decode() تقریباً ۳۵۰ مگابایت heap تخصیص میدهد: رشته encoded به علاوه آرایه بایت decoded. decoder.wrap(InputStream) بهصورت لایو دیکد میکند و مصرف حافظه را ثابت نگه میدارد.
import java.util.Base64;
import java.io.*;
import java.nio.file.*;
public class StreamDecode {
public static void main(String[] args) throws IOException {
Path src = Path.of("database-dump.sql.b64");
Path dst = Path.of("database-dump.sql");
try (InputStream in = Base64.getMimeDecoder().wrap(
new BufferedInputStream(Files.newInputStream(src)));
OutputStream out = new BufferedOutputStream(Files.newOutputStream(dst))) {
byte[] buffer = new byte[8192];
int bytesRead;
long total = 0;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
total += bytesRead;
}
System.out.printf("Decoded %d bytes → %s%n", total, dst);
}
}
}در Java 9+ میتوانید حلقه خواندن را با in.transferTo(out) جایگزین کنید — همان کار را با کد کمتر انجام میدهد. اگر فایل ممکن است دارای شکست خط باشد (فایلهای PEM، خروجیهای ایمیل) از getMimeDecoder().wrap() بهجای getDecoder().wrap() استفاده کنید.
import java.util.Base64;
import java.io.*;
import java.nio.file.*;
public class StreamDecodeSimple {
public static void main(String[] args) throws IOException {
try (InputStream in = Base64.getMimeDecoder().wrap(
new BufferedInputStream(Files.newInputStream(Path.of("backup.tar.b64"))));
OutputStream out = Files.newOutputStream(Path.of("backup.tar"))) {
in.transferTo(out); // Java 9+
}
}
}getDecoder().wrap() شکست خط در استریم را تحمل نمیکند. اگر دادههای Base64 دارای newline هستند (شکستهشده در ۷۶ کاراکتر)، بهجای آن از getMimeDecoder().wrap() استفاده کنید — در غیر این صورت استریم بهآرامی خروجی خراب تولید میکند یا در جای نامعلومی exception پرتاب میکند.دیکد کردن payload JWT در Java بدون کتابخانه JWT
یک JWT سه بخش Base64url-encoded است که با نقطه به هم متصل شدهاند. بخش میانی payload است — قسمتی که در طول debugging به آن اهمیت میدهید. میتوانید آن را بدون import کردن jjwt یا Nimbus دیکد کنید. روی . تقسیم کنید، بخش دوم را با getUrlDecoder() دیکد کنید، و JSON حاصل را parse کنید:
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class JWTInspect {
public static String decodeJwtPayload(String token) {
String[] parts = token.split("\\.");
if (parts.length != 3) {
throw new IllegalArgumentException(
"Invalid JWT: expected 3 segments, got " + parts.length);
}
// JWT uses URL-safe Base64 without padding
byte[] payload = Base64.getUrlDecoder().decode(parts[1]);
return new String(payload, StandardCharsets.UTF_8);
}
public static void main(String[] args) {
String token = "eyJhbGciOiJSUzI1NiJ9"
+ ".eyJzdWIiOiJ1c3ItNjcyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIs"
+ "ImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJiaWxsaW5nIl19"
+ ".SIGNATURE_PLACEHOLDER";
String payload = decodeJwtPayload(token);
System.out.println(payload);
// {"sub":"usr-672","iss":"auth.example.com",
// "exp":1741956800,"roles":["admin","billing"]}
}
}اشتباهات رایج
در code review ها به هر یک از اینها برخوردهام، و دو مورد اول بخش عمده باگهای مرتبط با Base64 در محیط production سرویسهای جاوا را تشکیل میدهند.
مشکل: توکنهای JWT و access token های OAuth از الفبای URL-safe (- و _) استفاده میکنند. پاس دادن آنها به getDecoder() یک IllegalArgumentException پرتاب میکند زیرا - در الفبای Base64 استاندارد نیست.
راهحل: منبع داده خود را بررسی کنید: توکنهای سیستمهای احراز هویت به getUrlDecoder() نیاز دارند؛ پیوستهای MIME به getMimeDecoder() نیاز دارند.
String header = "eyJhbGciOiJSUzI1NiJ9";
byte[] decoded = Base64.getUrlDecoder().decode(header);
System.out.println(new String(decoded));
// {"alg":"RS256"}// JWT header — URL-safe, no padding String header = "eyJhbGciOiJSUzI1NiJ9"; byte[] decoded = Base64.getDecoder().decode(header); // IllegalArgumentException: Illegal base64 character 2d
مشکل: new String(bytes) از charset پیشفرض JVM استفاده میکند که بین محیطها متفاوت است. یک سرور Linux CI (UTF-8) و یک هاست Windows production (Cp1252) برای همان بایتها نتایج متفاوتی تولید میکنند.
راهحل: همیشه StandardCharsets.UTF_8 را بهعنوان آرگومان دوم پاس دهید.
byte[] decoded = Base64.getDecoder().decode(encoded); String result = new String(decoded, StandardCharsets.UTF_8); // consistent across all platforms
byte[] decoded = Base64.getDecoder().decode(encoded); String result = new String(decoded); // platform-dependent — may corrupt multi-byte characters
مشکل: رشتههای Base64 که از ترمینال paste میشوند یا از فایلهای config خوانده میشوند اغلب دارای newline انتهایی هستند. دیکودر پایه هر کاراکتری خارج از الفبای Base64 را رد میکند.
راهحل: قبل از دیکد .strip() را روی ورودی فراخوانی کنید، یا به getMimeDecoder() سوئیچ کنید که whitespace را نادیده میگیرد.
String encoded = System.getenv("DB_PASSWORD_B64");
byte[] decoded = Base64.getDecoder().decode(encoded.strip());
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// postgres// Read from environment variable — has a trailing newline
String encoded = System.getenv("DB_PASSWORD_B64"); // "cG9zdGdyZXM=
"
byte[] decoded = Base64.getDecoder().decode(encoded);
// IllegalArgumentException: Illegal base64 character aمشکل: فراخوانی new String(decoded) روی محتوای باینری (تصاویر، protobuf، blob های رمزگذاریشده) یک String نامعتبر تولید میکند. تبدیل آن به بایت بعداً بهآرامی داده را خراب میکند زیرا سازنده String دنبالههای نامعتبر UTF-8 را جایگزین میکند.
راهحل: دادههای باینری را در تمام pipeline خود بهصورت byte[] نگه دارید. تنها زمانی به String تبدیل کنید که مطمئن هستید محتوا متن است.
byte[] decoded = Base64.getDecoder().decode(pngBase64);
// Write bytes directly — no String conversion
Files.write(Path.of("image.png"), decoded);byte[] decoded = Base64.getDecoder().decode(pngBase64);
String imageStr = new String(decoded); // corrupts binary
Files.writeString(Path.of("image.png"), imageStr); // broken fileمقایسه متدها
دیکودرهای داخلی اکثر موارد استفاده را پوشش میدهند. Apache Commons Codec و Guava جایگزینهایی هستند که ممکن است در codebases قدیمیتر با آنها مواجه شوید.
برای توکنهای JWT و payload های API مدرن: getUrlDecoder(). برای پیوستهای ایمیل و گواهینامههای PEM: getMimeDecoder(). برای فایلهای بزرگ که حافظه اهمیت دارد: decoder.wrap(InputStream). همه چیز دیگر: getDecoder(). Apache Commons Codec تنها زمانی منطقی است که از قبل در درخت وابستگی شما باشد.
برای تأیید سریع در طول توسعه، دیکودر Base64 آنلاین از نوشتن یک کلاس one-off سریعتر است.
سوالات متداول
چطور یک رشته Base64 را در Java دیکد کنم؟
java.util.Base64 را import کرده و Base64.getDecoder().decode(encodedString) را فراخوانی کنید. این متد یک byte[] برمیگرداند — برای دریافت متن خوانا آن را با new String(bytes, StandardCharsets.UTF_8) تبدیل کنید. برای Base64 URL-safe (که در JWTها استفاده میشود)، getDecoder() را با getUrlDecoder() جایگزین کنید.
import java.util.Base64;
import java.nio.charset.StandardCharsets;
byte[] decoded = Base64.getDecoder().decode("c2VydmVyLWNvbmZpZw==");
String result = new String(decoded, StandardCharsets.UTF_8);
System.out.println(result); // server-configتفاوت بین getDecoder() و getMimeDecoder() در Java چیست؟
getDecoder() سختگیرانه عمل میکند — هر کاراکتری خارج از الفبای Base64، از جمله شکست خط، را رد میکند. getMimeDecoder() جداکنندههای خط (\r\n) را تحمل میکند و هر کاراکتر غیر Base64 را نادیده میگیرد، بنابراین برای دیکد کردن پیوستهای ایمیل و گواهینامههای PEM که داده در آنها در ۷۶ کاراکتر شکسته شده، گزینه مناسبی است.
String wrapped = "c2VydmVyLWNv\r\nbmZpZw=="; // getDecoder() throws IllegalArgumentException // Base64.getDecoder().decode(wrapped); // FAILS // getMimeDecoder() handles it byte[] decoded = Base64.getMimeDecoder().decode(wrapped); System.out.println(new String(decoded)); // server-config
چطور یک رشته Base64 URL-safe را در Java دیکد کنم؟
از Base64.getUrlDecoder().decode(encoded) استفاده کنید. دیکودر URL انتظار دارد الفبای - و _ تعریفشده در RFC 4648 §5 بهجای + و / باشد. توکنهای JWT همیشه از این الفبا استفاده میکنند. اگر کاراکترهای پدینگ (=) حذف شده باشند (که در JWTها رایج است)، دیکودر URL آن را مدیریت میکند — دیکودر URL جاوا هم ورودی با پدینگ و هم بدون پدینگ را میپذیرد.
import java.util.Base64;
// JWT header — URL-safe, no padding
String jwtHeader = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
byte[] decoded = Base64.getUrlDecoder().decode(jwtHeader);
System.out.println(new String(decoded));
// {"alg":"HS256","typ":"JWT"}چطور یک فایل Base64 بزرگ را بهصورت استریم در Java دیکد کنم؟
از decoder.wrap(inputStream) برای پوشاندن یک FileInputStream استفاده کنید. InputStream بازگشتی Base64 را بهصورت لایو در هنگام خواندن بایتها دیکد میکند، بنابراین مصرف حافظه صرفنظر از اندازه فایل ثابت میماند. آن را از طریق یک BufferedInputStream یا مستقیم به Files.copy() هدایت کنید تا بهترین توان عملیاتی داشته باشید.
import java.util.Base64;
import java.io.*;
import java.nio.file.*;
try (InputStream in = Base64.getDecoder().wrap(
new BufferedInputStream(new FileInputStream("payload.b64")));
OutputStream out = new FileOutputStream("payload.bin")) {
in.transferTo(out);
}چرا Base64.getDecoder().decode() خطای IllegalArgumentException میدهد؟
دیکودر پایه سختگیرانه است: شکست خط، فاصله، و هر کاراکتری خارج از A-Za-z0-9+/= را رد میکند. سه دلیل رایج: ورودی دارای newline انتهایی است (آن را trim کنید)، ورودی از کاراکترهای URL-safe مانند - و _ استفاده میکند (به getUrlDecoder() سوئیچ کنید)، یا ورودی در ۷۶ کاراکتر شکسته شده است (به getMimeDecoder() سوئیچ کنید). اگر پیام خطا مبهم بود، بایتهای خام را بررسی کنید.
String raw = "c2VydmVyLWNvbmZpZw==\n"; // trailing newline // Option 1: trim whitespace byte[] decoded = Base64.getDecoder().decode(raw.strip()); // Option 2: use MIME decoder which ignores whitespace byte[] decoded2 = Base64.getMimeDecoder().decode(raw);
آیا میتوانم بدون java.util.Base64 در Java دیکد کنم؟
بله، اما در Java 8+ دلیل خوبی برای این کار وجود ندارد. قبل از Java 8، توسعهدهندگان از sun.misc.BASE64Decoder (داخلی، در Java 9+ حذف شد)، javax.xml.bind.DatatypeConverter.parseBase64Binary() (در Java 11 حذف شد)، یا Apache Commons Codec استفاده میکردند. هر سه یا منسوخ شدهاند یا به وابستگی اضافی نیاز دارند. از java.util.Base64 استفاده کنید — سریعتر است، با JDK عرضه میشود، و هر سه نوع (basic، URL-safe، MIME) را پوشش میدهد.
ابزارهای مرتبط
- رمزگذار Base64 — متن یا دادههای باینری را در مرورگر به Base64 کدگذاری کنید، برای تولید test fixture جهت paste کردن در unit test های جاوا مناسب است.
- دیکودر JWT — هر سه بخش JWT را یکدفعه تقسیم و دیکد کنید، با بررسی فیلد به فیلد payload — وقتی فقط میخواهید یک توکن بخوانید از نوشتن یک کلاس جاوا سریعتر است.
- دیکودر URL — رشتههای URL-encoded را percent-decode کنید، مفید است وقتی پاسخهای API دادههای Base64url را با پارامترهای query percent-encoded ترکیب میکنند.
- قالببندی JSON — پس از دیکد کردن یک payload JWT یا config API بهصورت Base64، JSON را اینجا paste کنید تا ساختار آن را pretty-print و اعتبارسنجی کنید.