فك ترميز Base64 في Java أمرٌ أجد نفسي بحاجة إليه كل أيام قليلة — استخراج الأسرار من متغيرات بيئة Kubernetes، قراءة الحمولات الثنائية من واجهات REST البرمجية، وفحص رموز JWT خلال جلسات تصحيح الأخطاء. توفر لغة Java صنف java.util.Base64 المدمج (منذ JDK 8) بثلاثة أنواع من التفكيك: getDecoder() لـ Base64 القياسي، وgetUrlDecoder() للمدخلات الآمنة للـ URL، وgetMimeDecoder() للبيانات الملفوفة في أسطر كمرفقات البريد الإلكتروني. لإجراء فحص سريع دون كتابة كود، مُفكك Base64 من ToolDeck يُنجز المهمة فوراً في متصفحك. يستهدف هذا الدليل Java 8+ ويتناول الأنواع الثلاثة للتفكيك، والتدفق باستخدام wrap(InputStream)، واستخراج حمولة JWT، وفك ترميز الملفات واستجابات واجهات البرمجة، وApache Commons Codec كبديل، والأخطاء الأربعة التي تُنتج مخرجات فاسدة في بيئة الإنتاج.
- ✓Base64.getDecoder().decode(s) هو الأسلوب القياسي — مدمج في java.util.Base64 منذ JDK 8، لا تبعيات مطلوبة.
- ✓استخدم getUrlDecoder() لرموز JWT وحمولات OAuth — فهي تستخدم حروف - و_، وليس + و/.
- ✓getMimeDecoder() يتجاهل فواصل الأسطر والمسافات البيضاء، مما يجعله الخيار المناسب لمرفقات البريد وشهادات PEM.
- ✓decoder.wrap(InputStream) يُفكك أثناء التدفق للملفات الكبيرة دون تحميل كل شيء في الذاكرة.
- ✓المُفكك الأساسي صارم — الأسطر الجديدة الزائدة، والمسافات، أو حروف أبجدية خاطئة تُطلق IllegalArgumentException فوراً.
ما هو فك ترميز Base64؟
يحوّل ترميز Base64 البيانات الثنائية إلى تمثيل ASCII من 64 حرفاً حتى يمكن نقلها بأمان عبر البروتوكولات النصية — حقول JSON وترويسات HTTP ومستندات XML وأجسام البريد الإلكتروني. فك الترميز يعكس هذا: كل 4 أحرف Base64 تُحوَّل إلى 3 بايتات أصلية. حشو = في النهاية يُشير إلى عدد البايتات المُضافة لملء المجموعة الأخيرة. Base64 ليس تشفيراً — يستطيع أي شخص عكسه. الغرض منه هو أمان النقل، وليس السرية.
أكثر حالات التفكيك شيوعاً في Java: استخراج قيم الإعدادات المُمرَّرة كمتغيرات بيئة مُرمَّزة بـ Base64، واستخراج الملفات الثنائية من استجابات واجهات السحابة البرمجية، وقراءة الشهادات المُرمّزة بـ PEM، وفحص حمولات رموز JWT أثناء تصحيح الأخطاء.
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
}
}حدّد دائماً 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
}
}التفكيك إلى مخزن مُخصص مسبقاً
الحمل الزائد ذو ثلاثة معامِلات decode(byte[] src, byte[] dst) يكتب مباشرةً في مخزن الوجهة ويُعيد عدد البايتات المكتوبة. يتجنب هذا تخصيصاً إضافياً في المسارات الساخنة:
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، أو كائن Java مُسلسَل، أو رسالة protobuf، أو طابع زمني. المُفكك نفسه يُعيد دائماً بايتات — تحويلها إلى النوع المطلوب مسؤوليتك.
من 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 إلى كائن Java باستخدام 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 غير موثوقة. هجمات إلغاء التسلسل في Java موثقة جيداً — إذا كان المحتوى المُرمَّز يأتي من مصدر خارجي، قم بتحليله كـ JSON أو protobuf بدلاً من استخدام التسلسل الأصلي في Java.مرجع دوال Base64.Decoder
جميع الدوال تنتمي إلى java.util.Base64 وصنفه الداخلي Base64.Decoder. الدوال المصنعية الثلاث على Base64 تُعيد نسخاً مختلفة من المُفككات؛ أما دالتا decode() وwrap() فتنتميان إلى نسخة Decoder.
getMimeDecoder() — تفكيك Base64 الملفوف في أسطر و MIME
المُفكك الأساسي يرفض أي شيء خارج حروف Base64 — وهذا يشمل فواصل الأسطر \r\n التي يحتويها دائماً المحتوى المُرمَّز بـ MIME. مرفقات البريد الإلكتروني وشهادات PEM وبعض استجابات واجهات برمجة قديمة تلف مخرجات Base64 عند 76 حرفاً في كل سطر. يتجاهل getMimeDecoder() بصمت فواصل الأسطر وأي حرف ليس في حروف Base64، فيتعامل مع هذا الأمر مباشرةً.
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() متساهل: يتخطى الأحرف غير الصالحة بدلاً من إطلاق استثناء. هذا مناسب لبيانات MIME المعروفة، لكنه قد يبتلع بصمت أي تلف في المدخلات العشوائية. استخدم getDecoder() عندما تريد تحققاً صارماً.تفكيك Base64 من ملف واستجابة واجهة برمجية
قراءة ملف مُرمَّز بـ Base64 من القرص
أحياناً تُخزَّن الملفات الثنائية (الصور والشهادات والكتل المشفرة) على القرص كنص 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 البرمجية
كثيراً ما تُعيد واجهات السحابة البرمجية (AWS KMS وGitHub Contents وVault) البيانات الثنائية كسلاسل Base64 داخل JSON. حلّل JSON أولاً، ثم فكّك الحقل المستهدف:
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 منفصلاً عن أخطاء الشبكة. خلط استثناءات الإدخال/الإخراج مع أخطاء التفكيك يُعقّد تصحيح الأخطاء — تريد أن تعرف فوراً هل أعادت الواجهة البرمجية بيانات سيئة أم أن الشبكة هي التي فشلت.فك ترميز Base64 من سطر الأوامر
لست بحاجة دائماً إلى برنامج Java. كل نظام Linux وmacOS يحتوي على أمر base64، ويأتي JDK 9+ مع jshell لأسطر Java التفاعلية الفردية. للفحص السريع أثناء تصحيح الأخطاء، هذه أسرع من كتابة صنف مؤقت وتصريفه.
# 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لنسخ السلاسل المُرمَّزة ولصقها مباشرةً في المتصفح، مُفكك Base64 من ToolDeck يتعامل مع كلا النوعين القياسي والآمن للـ URL دون أي إعداد.
بديل عالي الأداء: Apache Commons Codec
java.util.Base64 المدمج في Java مُحسَّن بالفعل — يستخدم JDK 11+ تعليمات intrinsics على x86 للترميز والتفكيك. بالنسبة لمعظم التطبيقات، لا يوجد سبب للجوء إلى مكتبة خارجية. ومع ذلك، يظل Apache Commons Codec شائعاً في قواعد الكود القديمة ويوفر Base64InputStream للتفكيك بالتدفق مع معالجة تلقائية للمسافات البيضاء.
<!-- 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 على الواجهة البرمجية المدمجة هي تساهله مع المسافات البيضاء افتراضياً وصنف Base64InputStream الذي سبق decoder.wrap() في Java. إذا كنت على Java 8+، فإن الواجهة البرمجية المدمجة تُغطي كل ما يفعله Commons Codec. أنا لا أستخدم Commons Codec إلا عندما يعتمد المشروع بالفعل عليه.
تدفق ملفات Base64 الكبيرة باستخدام decoder.wrap()
تحميل ملف Base64 بحجم 200 ميجابايت باستخدام Files.readString() ثم استدعاء decode() يُخصص نحو 350 ميجابايت من الكومة: السلسلة المُرمَّزة بالإضافة إلى مصفوفة البايتات المُفككة. يُفكك 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) — تفعل الشيء ذاته بكود أقل. استخدم getMimeDecoder().wrap() بدلاً من getDecoder().wrap() إذا كان الملف قد يحتوي على فواصل أسطر (ملفات PEM، صادرات البريد الإلكتروني).
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 تحتوي على أسطر جديدة (ملفوفة عند 76 حرفاً)، استخدم getMimeDecoder().wrap() بدلاً من ذلك — وإلا فإن التدفق ينتج مخرجات تالفة بصمت أو يُطلق استثناءً عند موضع قراءة غير متوقع.فك ترميز حمولة JWT Base64 في Java بدون مكتبة JWT
JWT عبارة عن ثلاثة مقاطع مُرمَّزة بـ Base64url مفصولة بنقاط. المقطع الأوسط هو الحمولة — الجزء الذي يهمك أثناء تصحيح الأخطاء. يمكنك فك ترميزه دون استيراد jjwt أو Nimbus. قسّمه بـ .، فكّك الجزء الثاني باستخدام getUrlDecoder()، وحلّل JSON الناتج منه:
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"]}
}
}الأخطاء الشائعة
صادفت كل واحدة من هذه الأخطاء في مراجعات الكود، والأولتان تمثلان الغالبية العظمى من أخطاء الإنتاج المتعلقة بـ Base64 في خدمات Java.
المشكلة: رموز JWT وتوكنات الوصول 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) مجموعة الأحرف الافتراضية لـ JVM، والتي تختلف بين البيئات. خادم Linux على CI (UTF-8) وخادم Windows الإنتاجي (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 المنسوخة من الطرفيات أو المقروءة من ملفات الإعداد غالباً ما تحتوي على أسطر جديدة زائدة. يرفض المُفكك الأساسي أي حرف خارج حروف Base64.
الحل: استدعِ .strip() على المدخل قبل التفكيك، أو تحوّل إلى getMimeDecoder() الذي يتجاهل المسافات البيضاء.
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، كتل مشفرة) ينتج سلسلة غير صالحة. إعادة تحويلها إلى بايتات لاحقاً يُفسد البيانات بصمت لأن منشئ String يستبدل متتاليات UTF-8 غير الصالحة.
الحل: احتفظ بالبيانات الثنائية كـ 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 هما بديلان قد تصادفهما في قواعد الكود القديمة.
لرموز JWT وحمولات واجهات برمجة حديثة: getUrlDecoder(). لمرفقات البريد الإلكتروني وشهادات PEM: getMimeDecoder(). للملفات الكبيرة حيث تهم الذاكرة: decoder.wrap(InputStream). لكل شيء آخر: getDecoder(). Apache Commons Codec منطقي فقط إذا كان موجوداً بالفعل في شجرة التبعيات.
للتحقق السريع أثناء التطوير، مُفكك Base64 الإلكتروني أسرع من كتابة صنف مؤقت.
الأسئلة الشائعة
كيف أُفكك سلسلة Base64 في Java؟
استورد java.util.Base64 واستدعِ Base64.getDecoder().decode(encodedString). تُعيد الدالة byte[] — حوّلها إلى نص باستخدام new String(bytes, StandardCharsets.UTF_8). بالنسبة لـ Base64 الآمن للـ URL (المستخدم في JWTs)، استبدل 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 حيث تكون البيانات ملفوفة عند 76 حرفاً في السطر.
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 في Java؟
استخدم Base64.getUrlDecoder().decode(encoded). يتوقع مُفكك الـ URL حروف - و_ المُعرَّفة في RFC 4648 §5 بدلاً من + و/. تستخدم رموز JWT دائماً هذا النوع من الحروف. إذا أُزيلت حروف الحشو (=) — وهو شائع في JWTs — فإن مُفكك الـ 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+/=. الأسباب الشائعة الثلاثة: المدخل يحتوي على أسطر جديدة (نظّفها)، المدخل يستخدم حروف الـ URL-safe مثل - و_ (تحوّل إلى getUrlDecoder())، أو المدخل ملفوف عند 76 حرفاً (تحوّل إلى 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);
هل يمكنني فك ترميز Base64 في Java بدون java.util.Base64؟
نعم، لكن لا يوجد سبب وجيه لذلك على Java 8+. قبل Java 8، كان المطورون يستخدمون sun.misc.BASE64Decoder (داخلي، أُزيل في Java 9+)، أو javax.xml.bind.DatatypeConverter.parseBase64Binary() (أُزيل في Java 11)، أو Apache Commons Codec. الثلاثة إما مُهملة أو تتطلب تبعية إضافية. التزم بـ java.util.Base64 — فهو أسرع، ومشمول مع JDK، ويغطي الأنواع الثلاثة (أساسي، آمن للـ URL، MIME).
أدوات ذات صلة
- Base64 Encoder — رمّز نصاً أو بيانات ثنائية إلى Base64 في المتصفح، مفيد لتوليد بيانات اختبار للصق في اختبارات الوحدة في Java.
- JWT Decoder — يقسّم ويفكّك جميع مقاطع JWT الثلاثة دفعةً واحدة مع فحص الحمولة حقلاً حقلاً — أسرع من كتابة صنف Java عندما تحتاج فقط إلى فحص رمز.
- URL Decoder — فكّ ترميز السلاسل المُرمَّزة بـ percent، مفيد عندما تجمع استجابات واجهات البرمجة بين بيانات Base64url ومعاملات استعلام مُرمَّزة بالنسبة المئوية.
- JSON Formatter — بعد فك ترميز حمولة JWT Base64 أو إعداد واجهة برمجية، الصق JSON هنا لتنسيقه والتحقق من بنيته.