ToolDeck

رمزگذاری Base64 در Java — مثال‌های java.util.Base64

·Java Security & API Engineer·بررسی‌شده توسطPavel Novak·منتشر شده

از رمزگذاری Base64 آنلاین آنلاین رایگان مستقیم در مرورگرتان استفاده کنید — نیازی به نصب نیست.

امتحان کردن رمزگذاری Base64 آنلاین آنلاین ←

هر بار که یک header احراز هویت HTTP Basic راه‌اندازی می‌کنم، یک گواهینامه در یک Kubernetes secret جاسازی می‌کنم، یا داده باینری را از طریق یک API JSON ارسال می‌کنم، اولین قدم همیشه یکسان است: رمزگذاری Base64 بایت‌های خام به یک رشته ASCII-safe. Java این کار را با java.util.Base64 ساده می‌کند — API استاندارد موجود از Java 8 که جایگزین sun.misc.BASE64Encoder منسوخ شد. برای رمزگذاری سریع بدون نوشتن کد، Base64 Encoder ToolDeck همین کار را مستقیم در مرورگر انجام می‌دهد. این راهنما شامل Base64.getEncoder()، getUrlEncoder()، getMimeEncoder()، رمزگذاری فایل، استریمینگ با wrap(OutputStream)، و اشتباهاتی است که حتی برنامه‌نویسان باتجربه Java را به دردسر می‌اندازد. تمام مثال‌ها روی Java 8 تا Java 21+ کامپایل می‌شوند.

  • Base64.getEncoder().encodeToString(bytes) یک‌خط استاندارد است — از Java 8 در JDK تعبیه شده و تا Java 17 و 21 بدون تغییر است.
  • همیشه StandardCharsets.UTF_8 را به String.getBytes() بدهید — بدون آن از charset پیش‌فرض پلتفرم استفاده می‌شود که بین JVMهای مختلف فرق می‌کند.
  • getUrlEncoder() خروجی URL-safe تولید می‌کند (- به‌جای +، _ به‌جای /) و withoutPadding() کاراکترهای = دنباله را حذف می‌کند.
  • getMimeEncoder() هر ۷۶ کاراکتر شکست خط درج می‌کند — که برای ایمیل (MIME) و فرمت گواهینامه PEM لازم است.
  • برای فایل‌های بزرگ، از Base64.getEncoder().wrap(OutputStream) برای استریم بدون بارگذاری کل فایل در حافظه استفاده کنید.

رمزگذاری Base64 چیست؟

Base64 داده باینری دلخواه را به رشته‌ای از ۶۴ کاراکتر ASCII قابل چاپ تبدیل می‌کند: A-Z، a-z، 0-9، +، و /. هر ۳ بایت ورودی دقیقاً ۴ کاراکتر Base64 تولید می‌کند. اگر طول ورودی مضرب ۳ نباشد، یک یا دو = کاراکتر padding اضافه می‌شود. خروجی رمزگذاری‌شده همیشه تقریباً ۳۳٪ بزرگ‌تر از داده اصلی است.

Base64 رمزنگاری نیست. هر کسی با رشته رمزگذاری‌شده می‌تواند آن را رمزگشایی کند. هدف آن امنیت انتقال است: header‌های HTTP، پیلودهای JSON، اسناد XML، و بدنه ایمیل‌ها پروتکل‌های متن‌محور هستند که نمی‌توانند بدون خرابی بایت‌های باینری خام حمل کنند. موارد استفاده رایج Java شامل احراز هویت HTTP Basic، جاسازی گواهینامه‌های PEM، ذخیره داده باینری در ستون‌های متنی پایگاه داده، و ساخت بخش‌های JWT token است.

After · text
Before · text
ZGVwbG95LXN2Yzpza19saXZlXzRlQzM5SHFMeWpXRGFyanRUMXpkcDdkYw==
deploy-svc:sk_live_4eC39HqLyjWDarjtT1zdp7dc

Base64.getEncoder().encodeToString() — API استاندارد

java.util.Base64 در Java 8 به‌عنوان جایگزین رسمی sun.misc.BASE64Encoder معرفی شد. این کلاس سه متد factory استاتیک فراهم می‌کند — هر کدام یک نمونه کلاس تودرتوی Base64.Encoder را برمی‌گرداند — که سه نوع Base64 تعریف‌شده در RFC 4648 را پوشش می‌دهد. نیازی به کتابخانه شخص ثالث نیست. هیچ وابستگی Maven لازم نیست. فقط import کنید و فراخوانی کنید.

مثال ساده — رمزگذاری یک String

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class EncodeDemo {
    public static void main(String[] args) {
        String credentials = "monitoring-svc:9f2a7c4e-b1d8-4a3f";
        byte[] credentialBytes = credentials.getBytes(StandardCharsets.UTF_8);

        String encoded = Base64.getEncoder().encodeToString(credentialBytes);
        System.out.println(encoded);
        // bW9uaXRvcmluZy1zdmM6OWYyYTdjNGUtYjFkOC00YTNm
    }
}

نکته کلیدی که اکثر برنامه‌نویسان Java در بار اول از دست می‌دهند: یک String باید قبل از رمزگذاری به byte[] تبدیل شود. Base64 روی بایت‌ها کار می‌کند، نه کاراکترها. encodeToString() یک byte[] می‌پذیرد و مستقیماً String رمزگذاری‌شده Base64 را برمی‌گرداند. اگر نتیجه رمزگذاری‌شده را به‌صورت بایت نیاز دارید، از encode(byte[]) استفاده کنید — این byte[] از کاراکترهای Base64 رمزگذاری‌شده ASCII برمی‌گرداند، که وقتی مستقیماً به یک OutputStream می‌نویسید یا فریم‌های پروتکل باینری می‌سازید مفید است.

HTTP Basic Auth — رایج‌ترین مورد استفاده

احراز هویت HTTP Basic احتمالاً تنها رایج‌ترین دلیلی است که برنامه‌نویسان Java سراغ رمزگذاری Base64 می‌روند. مشخصات (RFC 7617) الزام می‌کند که رشته اعتبارنامه username:password به Base64 رمزگذاری شده و در header Authorization قرار گیرد. بارها دیده‌ام که این کار اشتباه انجام می‌شود — معمولاً با فراموش کردن جداکننده دونقطه یا رمزگذاری جداگانه اجزا.

Java — HTTP Basic Auth header
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class BasicAuthExample {
    public static void main(String[] args) throws Exception {
        String username = "metrics-exporter";
        String apiKey = "sk_live_4eC39HqLyjWDarjtT1zdp7dc";

        // username:password → Base64
        String credentials = username + ":" + apiKey;
        String authHeader = "Basic " + Base64.getEncoder()
            .encodeToString(credentials.getBytes(StandardCharsets.UTF_8));

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/v2/metrics"))
            .header("Authorization", authHeader)
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.statusCode());  // 200
    }
}

Round-Trip — رمزگذاری و رمزگشایی

Java 8+ — encode and decode round-trip
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class RoundTrip {
    public static void main(String[] args) {
        String original = "X-Correlation-ID: req_8a4f2c91-e7b3-4d56-9012-3f7a8b9c0d1e";

        // Encode
        String encoded = Base64.getEncoder()
            .encodeToString(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(encoded);
        // WC1Db3JyZWxhdGlvbi1JRDogcmVxXzhhNGYyYzkxLWU3YjMtNGQ1Ni05MDEyLTNmN2E4YjljMGQxZQ==

        // Decode
        byte[] decodedBytes = Base64.getDecoder().decode(encoded);
        String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

        System.out.println(original.equals(decoded));  // true
    }
}
توجه:API کلاس java.util.Base64 از Java 8 تا Java 17 و Java 21 یکسان است. هنگام ارتقای JDK نیازی به migration نیست. همان کد روی هر نسخه از Java 8 به بعد کامپایل و اجرا می‌شود.

رمزگذاری داده غیر-رشته‌ای — byte[]، UUID، و Timestamp‌ها

رمزگذاری Base64 در Java همیشه با یک byte[] شروع می‌شود. رشته‌ها از طریق getBytes(StandardCharsets.UTF_8) تبدیل می‌شوند، اما سایر انواع نیاز به یک مرحله تبدیل دارند. UUID‌ها، timestamp‌ها، و شناسه‌های عددی باید قبل از رمزگذاری Base64 به یک رشته یا نمایش بایت سریال‌سازی شوند.

UUID — رمزگذاری به‌عنوان نمایش رشته‌ای

Java — Base64 encoding a UUID
import java.util.Base64;
import java.util.UUID;
import java.nio.charset.StandardCharsets;

UUID sessionId = UUID.fromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
String encoded = Base64.getEncoder()
    .encodeToString(sessionId.toString().getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
// NmJhN2I4MTAtOWRhZC0xMWQxLTgwYjQtMDBjMDRmZDQzMGM4

UUID فشرده — رمزگذاری ۱۶ بایت خام

اگر نتیجه رمزگذاری کوتاه‌تری می‌خواهید، ۱۲۸ بیت UUID را به‌عنوان ۱۶ بایت خام استخراج کنید به‌جای تبدیل به فرم رشته‌ای ۳۶-کاراکتری. خروجی Base64 از ۴۸ کاراکتر به ۲۴ کاهش می‌یابد.

Java — compact UUID encoding
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.UUID;

UUID eventId = UUID.fromString("550e8400-e29b-41d4-a716-446655440000");

ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(eventId.getMostSignificantBits());
buffer.putLong(eventId.getLeastSignificantBits());

String compact = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(buffer.array());
System.out.println(compact);
// VQ6EAOKbQdSnFkRmVUQAAA
// 22 chars vs 48 for the string-based approach

Timestamp و پیلود ترکیبی

Java — encoding a JSON-like payload with timestamp
import java.time.Instant;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// شبیه‌سازی یک پیلود به سبک JWT
String payload = String.format(
    "{"sub":"usr_7b3c","iss":"auth.internal","iat":%d,"exp":%d}",
    Instant.now().getEpochSecond(),
    Instant.now().plusSeconds(3600).getEpochSecond()
);

String encoded = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(payload.getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
// eyJzdWIiOiJ1c3JfN2IzYyIsImlzcyI6ImF1dGguaW50ZXJuYWwiLCJpYXQiOj... (URL-safe, no padding)
هشدار:برای دریافت محتوای یک byte[] روی آن toString() فراخوانی نکنید — این کار هش هویت آرایه مثل [B@6d06d69c را می‌دهد. از new String(bytes, StandardCharsets.UTF_8) استفاده کنید یا آرایه بایت را مستقیماً به encodeToString() بدهید.

مرجع متدهای Base64.Encoder

کلاس java.util.Base64 سه متد factory ارائه می‌کند که هر کدام یک Base64.Encoder پیکربندی‌شده برای یک نوع خاص برمی‌گرداند. نمونه‌های رمزگذار thread-safe و stateless هستند — یک بار بسازید و مجدداً استفاده کنید.

متد
نوع
توضیح
getEncoder()
Base64.Encoder
یک رمزگذار پایه RFC 4648 با الفبای استاندارد (A-Z, a-z, 0-9, +, /) برمی‌گرداند
getUrlEncoder()
Base64.Encoder
یک رمزگذار با الفبای URL-safe (- به‌جای +، _ به‌جای /) برمی‌گرداند
getMimeEncoder()
Base64.Encoder
یک رمزگذار MIME که هر ۷۶ کاراکتر یک \r\n درج می‌کند برمی‌گرداند
getMimeEncoder(lineLength, lineSeparator)
Base64.Encoder
رمزگذار MIME با طول خط و بایت‌های جداکننده سفارشی
encoder.withoutPadding()
Base64.Encoder
یک رمزگذار بدون کاراکترهای = پایانی برمی‌گرداند
encoder.encode(byte[])
byte[]
آرایه بایت را رمزگذاری کرده و آرایه بایت رمزگذاری‌شده برمی‌گرداند
encoder.encodeToString(byte[])
String
آرایه بایت را رمزگذاری کرده و مستقیماً String رمزگذاری‌شده برمی‌گرداند
encoder.wrap(OutputStream)
OutputStream
یک OutputStream برای رمزگذاری Base64 به‌صورت استریم می‌پوشاند

Base64.getUrlEncoder() — رمزگذاری URL-Safe

رمزگذار URL-safe از یک الفبای جایگزین استفاده می‌کند که در آن + به - و / به _ تبدیل می‌شود، طبق تعریف RFC 4648 بخش ۵. این موضوع زمانی اهمیت دارد که رشته Base64 در یک پارامتر query URL، نام فایل، یا مقدار cookie ظاهر شود — کاراکترهای Base64 استاندارد با جداکننده‌های URL و کاراکترهای رزرو شده سیستم فایل تداخل دارند.

Java — URL-safe Base64 encoding
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String redirectUri = "https://app.internal/callback?state=auth_pending&nonce=9f2a7c";
byte[] data = redirectUri.getBytes(StandardCharsets.UTF_8);

// رمزگذار استاندارد — شامل + و / که URL را خراب می‌کنند
String standard = Base64.getEncoder().encodeToString(data);
System.out.println(standard);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s/c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// رمزگذار URL-safe — برای پارامترهای query و نام فایل‌ها امن است
String urlSafe = Base64.getUrlEncoder().encodeToString(data);
System.out.println(urlSafe);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw==

// URL-safe بدون padding — برای JWT و توکن‌های فشرده
String noPadding = Base64.getUrlEncoder().withoutPadding().encodeToString(data);
System.out.println(noPadding);
// aHR0cHM6Ly9hcHAuaW50ZXJuYWwvY2FsbGJhY2s_c3RhdGU9YXV0aF9wZW5kaW5nJm5vbmNlPTlmMmE3Yw

نوع withoutPadding() کاراکترهای دنباله‌دار = را حذف می‌کند. مشخصات JWT نیاز دارند که Base64 URL-safe بدون padding برای بخش‌های header و payload باشد، بنابراین getUrlEncoder().withoutPadding() دقیقاً همان فراخوانی است که هنگام ساخت یا دستکاری دستی توکن‌های JWT می‌خواهید.

توجه:متد withoutPadding() یک نمونه رمزگذار جدید برمی‌گرداند — نمونه اصلی را تغییر نمی‌دهد. هر دو می‌توانند به فیلدهای static final اختصاص داده شوند و در thread‌ها به‌طور ایمن مجدداً استفاده شوند.

رمزگذاری از فایل و پاسخ API

دو رایج‌ترین سناریوی دنیای واقعی برای رمزگذاری Base64 در Java: خواندن یک فایل باینری از دیسک (گواهینامه‌ها، تصاویر، بسته‌های پیکربندی) و رمزگذاری داده دریافتی از یک پاسخ HTTP.

رمزگذاری یک فایل به Base64

Java — encoding a file
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

public class FileEncoder {
    public static void main(String[] args) {
        try {
            byte[] fileBytes = Files.readAllBytes(Path.of("certs/server.pem"));
            String encoded = Base64.getEncoder().encodeToString(fileBytes);

            System.out.printf("Original: %d bytes%n", fileBytes.length);
            System.out.printf("Encoded:  %d chars%n", encoded.length());

            // Write encoded content to a text file
            Files.writeString(
                Path.of("certs/server.pem.b64"),
                encoded
            );
        } catch (java.io.IOException e) {
            System.err.println("Failed to read file: " + e.getMessage());
        }
    }
}

رمزگذاری بدنه پاسخ API

Java 11+ — encoding an HTTP response
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;

public class ApiEncoder {
    public static void main(String[] args) {
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.example.com/v2/reports/weekly.pdf"))
                .header("Authorization", "Bearer tok_8f2a9c3d")
                .build();

            HttpResponse<byte[]> response = client.send(
                request, HttpResponse.BodyHandlers.ofByteArray()
            );

            if (response.statusCode() == 200) {
                String encoded = Base64.getEncoder()
                    .encodeToString(response.body());
                System.out.printf("Encoded %d bytes → %d chars%n",
                    response.body().length, encoded.length());
            } else {
                System.err.printf("HTTP %d: %s%n",
                    response.statusCode(),
                    new String(response.body()));
            }
        } catch (Exception e) {
            System.err.println("Request failed: " + e.getMessage());
        }
    }
}

اگر فقط نیاز دارید یک فایل یا پاسخ API را paste کنید و خروجی Base64 را بدون نوشتن کد بگیرید، Base64 Encoder آنلاین هر دو ورودی متن و باینری را مدیریت می‌کند.

رمزگذاری Base64 از خط فرمان

گاهی فقط نیاز دارید یک رشته یا فایل را از ترمینال رمزگذاری کنید — بدون پروژه Java، بدون IDE، بدون مرحله build. اکثر سیستم‌های Unix دارای دستور base64 هستند، و اگر JDK نصب دارید، می‌توانید از jshell برای رویکرد بومی Java استفاده کنید.

Bash — command-line Base64 encoding
# macOS / Linux — encode a string
echo -n "deploy-bot:sk_prod_9f2a7c4e" | base64
# ZGVwbG95LWJvdDpza19wcm9kXzlmMmE3YzRl

# Encode a file
base64 < certs/server.pem > certs/server.pem.b64

# Using jshell (JDK 9+)
echo 'System.out.println(java.util.Base64.getEncoder().encodeToString("deploy-bot:sk_prod_9f2a7c4e".getBytes()))' | jshell -

# Using java directly with a one-liner
java -e 'System.out.println(java.util.Base64.getEncoder().encodeToString(args[0].getBytes()))' "my-secret"
# Note: java -e requires JDK 23+ (JEP 477)

رویکرد jshell به‌ویژه مفید است وقتی می‌خواهید تأیید کنید که کد Java شما همان خروجی ابزار Unix را تولید می‌کند، یا وقتی دارید یک عدم تطابق بین آنچه سرویس شما ارسال می‌کند و آنچه گیرنده انتظار دارد را دیباگ می‌کنید. خودم یک shell alias برایش نگه می‌دارم.

توجه:در macOS، دستور base64 از -D برای رمزگشایی استفاده می‌کند. در Linux (GNU coreutils) از -d استفاده می‌کند. رفتار رمزگذاری در هر دو یکسان است. پرچم -w 0 در Linux شکست خط در خروجی را غیرفعال می‌کند، که معمولاً هنگام pipe کردن به دستورات دیگر چیزی است که می‌خواهید.

Apache Commons Codec — جایگزین پرکارایی

برای اکثر برنامه‌ها، java.util.Base64 به اندازه کافی سریع است. اما اگر میلیون‌ها عملیات رمزگذاری در یک حلقه فشرده پردازش می‌کنید — مثلاً pipeline‌های ingestion لاگ یا message broker‌های پرتوان — Apache Commons Codec ارزش دارد benchmark بگیرید. از قبل از Java 8 هم وجود داشته و یک جایگزین آزمایش‌شده با سطح API کمی متفاوت ارائه می‌کند.

Java — Apache Commons Codec
// Maven: org.apache.commons:commons-codec:1.17.0
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets;

byte[] telemetryPayload = ("{"service":"metrics-collector","
    + ""host":"prod-east-07","
    + ""cpu_pct":72.4,"
    + ""mem_mb":3891,"
    + ""timestamp":1710523200}")
    .getBytes(StandardCharsets.UTF_8);

// رمزگذاری استاندارد
String encoded = Base64.encodeBase64String(telemetryPayload);

// رمزگذاری URL-safe
String urlSafe = Base64.encodeBase64URLSafeString(telemetryPayload);

// بررسی معتبر بودن رشته به‌عنوان Base64
boolean valid = Base64.isBase64(encoded);
System.out.println(valid);  // true

Apache Commons Codec همچنین Base64OutputStream و Base64InputStream برای سناریوهای استریمینگ فراهم می‌کند، و شامل یک متد validation است که رمزگذار JDK فاقد آن است. اگر Commons Codec از قبل در درخت وابستگی شما است (با بسیاری از پروژه‌های Apache همراه است)، دلیلی برای عدم استفاده از آن وجود ندارد.

Guava BaseEncoding

کتابخانه Guava گوگل شامل BaseEncoding است که یک API fluent برای Base64 با جداکننده‌های خط قابل تنظیم، کنترل padding، و پشتیبانی از الفبای استاندارد و URL-safe ارائه می‌کند. این API خوانایی دارد، اما اضافه کردن Guava (تقریباً ۳ مگابایت) صرفاً برای رمزگذاری Base64 چندان منطقی نیست. اگر Guava قبلاً برای collection‌ها یا utility‌های cache در پروژه شما وجود دارد، API رمزگذاری یک مزیت اضافه خوب است.

Java — Guava BaseEncoding
// Maven: com.google.guava:guava:33.1.0-jre
import com.google.common.io.BaseEncoding;
import java.nio.charset.StandardCharsets;

byte[] webhookPayload = ("{"event":"deployment.completed","
    + ""repo":"payments-api","
    + ""sha":"a7f2c91e4b3d","
    + ""environment":"production"}")
    .getBytes(StandardCharsets.UTF_8);

// Base64 استاندارد
String standard = BaseEncoding.base64().encode(webhookPayload);

// URL-safe
String urlSafe = BaseEncoding.base64Url().encode(webhookPayload);

// بدون padding
String noPad = BaseEncoding.base64Url().omitPadding().encode(webhookPayload);

// با جداکننده خط (سبک PEM)
String wrapped = BaseEncoding.base64()
    .withSeparator("\n", 64)
    .encode(webhookPayload);

Base64.getMimeEncoder() — خروجی MIME و PEM با شکست خط

رمزگذار MIME هر ۷۶ کاراکتر یک \r\n شکست خط درج می‌کند که با مشخصات MIME (RFC 2045) مطابقت دارد. گواهینامه‌های PEM، پیوست‌های ایمیل S/MIME، و برخی API‌های قدیمی این فرمت را انتظار دارند. رمزگذارهای استاندارد و URL-safe یک خط بدون وقفه تولید می‌کنند — اگر خروجی آن‌ها را به سیستمی که Base64 با شکست خط انتظار دارد بدهید، ممکن است بی‌صدا شکست بخورد یا داده را رد کند.

Java — MIME Base64 encoding
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// شبیه‌سازی بدنه گواهینامه PEM
byte[] certData = new byte[256];  // In practice, read from a .der file
new java.security.SecureRandom().nextBytes(certData);

// رمزگذار MIME پیش‌فرض — 76 کاراکتر در هر خط، جداکننده \r\n
String mimeEncoded = Base64.getMimeEncoder().encodeToString(certData);
System.out.println(mimeEncoded);
// QYx2K3p8Xg7JmN1R+wFkLd...  (76 chars)
// Ht5Bv9CzAq0PnSjYl8WxUe...  (76 chars)
// ...

// رمزگذار MIME سفارشی — 64 کاراکتر در هر خط (استاندارد PEM)، جداکننده \n
Base64.Encoder pemEncoder = Base64.getMimeEncoder(64, new byte[]{'\n'});
String pemBody = pemEncoder.encodeToString(certData);
System.out.println("-----BEGIN CERTIFICATE-----");
System.out.println(pemBody);
System.out.println("-----END CERTIFICATE-----");
هشدار:از getMimeEncoder() برای توکن‌های JWT، header‌های HTTP، یا پارامترهای URL استفاده نکنید. شکست خط‌ها داده را در این زمینه‌ها خراب می‌کنند. به‌جای آن از getEncoder() یا getUrlEncoder() استفاده کنید.

استریمینگ فایل‌های بزرگ با Base64.getEncoder().wrap()

بارگذاری کل یک فایل در یک byte[] با Files.readAllBytes() برای فایل‌های کوچک کار می‌کند، اما برای هر چیزی بیش از ۵۰-۱۰۰ مگابایت خطر OutOfMemoryError وجود دارد. JDK دارای Base64.getEncoder().wrap(OutputStream) است که یک OutputStream برمی‌گرداند که هنگام نوشتن به آن داده را در پرواز رمزگذاری می‌کند. بایت‌های رمزگذاری‌شده بدون buffering کل ورودی به stream زیرین می‌روند.

Java — streaming Base64 encoding
import java.io.*;
import java.nio.file.*;
import java.util.Base64;

public class StreamingEncoder {
    public static void main(String[] args) throws IOException {
        Path inputPath = Path.of("backups/database-export.sql.gz");
        Path outputPath = Path.of("backups/database-export.sql.gz.b64");

        try (
            InputStream in = Files.newInputStream(inputPath);
            OutputStream fileOut = Files.newOutputStream(outputPath);
            OutputStream base64Out = Base64.getEncoder().wrap(fileOut)
        ) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            long totalBytes = 0;

            while ((bytesRead = in.read(buffer)) != -1) {
                base64Out.write(buffer, 0, bytesRead);
                totalBytes += bytesRead;
            }

            System.out.printf("Streamed %d bytes through Base64 encoder%n", totalBytes);
        }
        // Closing base64Out flushes the final padding bytes automatically
    }
}

بلوک try-with-resources flushing و بستن را مدیریت می‌کند. یک جزئیات که افراد را می‌گیرد: padding نهایی Base64 تنها زمانی نوشته می‌شود که OutputStream پوشاننده بسته شود. اگر آن را فراموش کنید (یا فقط stream خارجی را ببندید)، چند کاراکتر آخر خروجی رمزگذاری‌شده ممکن است گم شوند.

استریمینگ به Socket شبکه

متد wrap() با هر OutputStream کار می‌کند — خروجی فایل، خروجی socket، بدنه پاسخ HTTP، حتی ByteArrayOutputStream. در اینجا یک مثال نوشتن داده رمزگذاری‌شده Base64 مستقیماً به یک buffer در حافظه است، که برای unit test کردن یا ساختن پیلودهایی که از طریق HTTP ارسال می‌شوند مفید است:

Java — streaming to ByteArrayOutputStream
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Base64;
import java.nio.charset.StandardCharsets;

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

try (OutputStream encoder = Base64.getEncoder().wrap(buffer)) {
    // Write data in chunks — simulates reading from a stream
    encoder.write("chunk-1:telemetry-data-".getBytes(StandardCharsets.UTF_8));
    encoder.write("chunk-2:more-payload-".getBytes(StandardCharsets.UTF_8));
    encoder.write("chunk-3:final-segment".getBytes(StandardCharsets.UTF_8));
}

String encoded = buffer.toString(StandardCharsets.UTF_8);
System.out.println(encoded);
// Y2h1bmstMTp0ZWxlbWV0cnktZGF0YS1jaHVuay0yOm1vcmUtcGF5bG9hZC1jaHVuay0zOmZpbmFsLXNlZ21lbnQ=

// Verify round-trip
byte[] decoded = Base64.getDecoder().decode(encoded);
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// chunk-1:telemetry-data-chunk-2:more-payload-chunk-3:final-segment
توجه:اندازه buffer در مثال استریمینگ (۸۱۹۲ بایت) تصادفی نیست. با اندازه buffer پیش‌فرض استفاده‌شده توسط BufferedInputStream مطابقت دارد و یک تعادل خوب بین مصرف حافظه و overhead فراخوانی سیستم است. buffer‌های کوچک‌تر تعداد فراخوانی‌های read/write را افزایش می‌دهند؛ buffer‌های بزرگ‌تر بدون بهبود معنادار throughput حافظه هدر می‌دهند.

نمونه‌های رمزگذار Thread-Safe — ذخیره و استفاده مجدد

کلاس Base64.Encoder که توسط متدهای factory برگردانده می‌شود immutable و thread-safe است. فراخوانی Base64.getEncoder() در هر عملیات رمزگذاری هر بار یک شیء جدید می‌سازد. JVM احتمالاً این را بهینه می‌کند، اما ذخیره رمزگذار در یک فیلد static final نیت را واضح می‌کند و از allocation‌های غیرضروری در مسیرهای hot جلوگیری می‌کند.

Java — reusable encoder instances
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class TokenService {
    // یک بار بسازید، همه جا استفاده کنید — thread-safe
    private static final Base64.Encoder STANDARD = Base64.getEncoder();
    private static final Base64.Encoder URL_SAFE = Base64.getUrlEncoder().withoutPadding();
    private static final Base64.Encoder MIME = Base64.getMimeEncoder();

    public static String encodeForHeader(String value) {
        return STANDARD.encodeToString(value.getBytes(StandardCharsets.UTF_8));
    }

    public static String encodeForUrl(byte[] data) {
        return URL_SAFE.encodeToString(data);
    }

    public static String encodeForEmail(byte[] attachment) {
        return MIME.encodeToString(attachment);
    }
}

این الگو به‌ویژه در سرویس‌های Spring Boot مفید است که یک کلاس utility در چندین controller یا متد service رمزگذاری را مدیریت می‌کند. فراخوانی withoutPadding() یک نمونه رمزگذار جدید برمی‌گرداند، بنابراین می‌توانید هر دو نوع padding‌دار و بدون padding را به‌عنوان فیلدهای جداگانه ذخیره کنید. هر فراخوانی به encodeToString() یا encode() stateless است — نیازی به synchronization نیست، هیچ state mutable مشترکی وجود ندارد.

اشتباهات رایج

فراخوانی getBytes() بدون مشخص کردن charset

مشکل: String.getBytes() بدون آرگومان charset از encoding پیش‌فرض پلتفرم استفاده می‌کند، که در Windows برابر windows-1252، در اکثر سیستم‌های Linux برابر UTF-8 است و در macOS متفاوت است. همان کد بر روی ماشین‌های مختلف خروجی Base64 متفاوتی تولید می‌کند.

راه‌حل: همیشه StandardCharsets.UTF_8 را به‌صراحت بدهید.

After · Java
Before · Java
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(bytes);
String text = "Ключ доступа: prod-east";
byte[] bytes = text.getBytes();  // platform default — unpredictable
String encoded = Base64.getEncoder().encodeToString(bytes);
استفاده از رمزگذار استاندارد برای پارامترهای URL

مشکل: Base64.getEncoder() کاراکترهای + و / تولید می‌کند. وقتی در یک query string URL قرار می‌گیرند، + به‌عنوان فاصله و / به‌عنوان جداکننده path تفسیر می‌شوند و مقدار در سمت گیرنده بدون هیچ خطایی خراب می‌شود.

راه‌حل: از Base64.getUrlEncoder() برای هر مقداری که در URL ظاهر می‌شود استفاده کنید.

After · Java
Before · Java
// رمزگذاری URL-safe — بدون + یا /
String token = Base64.getUrlEncoder()
    .withoutPadding()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
// Token در پارامتر query URL — خراب می‌شود
String token = Base64.getEncoder()
    .encodeToString(sessionData);
String url = "https://auth.internal/verify?token=" + token;
رمزگشایی با نوع رمزگذار اشتباه

مشکل: رمزگذاری با getUrlEncoder() و رمزگشایی با getDecoder() (یا برعکس) باعث IllegalArgumentException می‌شود چون - و _ در الفبای Base64 استاندارد معتبر نیستند، و + و / در الفبای URL-safe معتبر نیستند.

راه‌حل: همیشه با decoder منطبق رمزگشایی کنید: getUrlDecoder() برای URL-safe، getDecoder() برای استاندارد.

After · Java
Before · Java
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Later...
byte[] decoded = Base64.getUrlDecoder()  // matching decoder
    .decode(encoded);
String encoded = Base64.getUrlEncoder()
    .encodeToString(data);
// Later...
byte[] decoded = Base64.getDecoder()  // WRONG decoder
    .decode(encoded);
// IllegalArgumentException if encoded contains - or _
بستن نشدن OutputStream مربوط به wrap()

مشکل: رمزگذار استریمینگ تا ۲ بایت ورودی را در انتظار یک گروه کامل ۳-بایتی buffer می‌کند. اگر OutputStream پوشاننده را نبندید، کاراکترهای نهایی ۱-۴ Base64 (شامل padding) هیچ‌گاه نوشته نمی‌شوند.

راه‌حل: از try-with-resources استفاده کنید، یا close() را صراحتاً روی stream پوشانده قبل از خواندن خروجی فراخوانی کنید.

After · Java
Before · Java
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (OutputStream b64os = Base64.getEncoder().wrap(baos)) {
    b64os.write(data);
}  // close() flushes final padding
String encoded = baos.toString();  // complete
ByteArrayOutputStream baos = new ByteArrayOutputStream();
 OutputStream b64os = Base64.getEncoder().wrap(baos);
b64os.write(data);
// baos.toString() is INCOMPLETE — missing final bytes

روش‌های رمزگذاری Base64 — مقایسه

متد
URL-Safe
استریمینگ
شکست خط
نوع سفارشی
نیاز به نصب
Base64.getEncoder()
✓ (wrap)
خیر (JDK 8+)
Base64.getUrlEncoder()
✓ (wrap)
خیر (JDK 8+)
Base64.getMimeEncoder()
✓ (wrap)
✓ (۷۶ کاراکتر)
خیر (JDK 8+)
Apache Commons Codec
وابستگی Maven
Guava BaseEncoding
✓ (قابل تنظیم)
وابستگی Maven
jcmd / CLI base64
✓ (pipe)
N/A
نصب سیستمی

برای اکثر پروژه‌ها: java.util.Base64 انتخاب درست است. هیچ وابستگی نیست، در JDK تعبیه شده، thread-safe، و هر سه نوع RFC 4648 را پوشش می‌دهد. تنها اگر Apache Commons Codec از قبل در classpath شما باشد و نیاز به متد validation isBase64() یا Base64OutputStream استریمینگ داشته باشید از آن استفاده کنید. BaseEncoding Guava گزینه معقولی است اگر پروژه شما از قبل به Guava وابسته است، اما اضافه کردن یک وابستگی ۳ مگابایتی صرفاً برای Base64 اصلاً توجیه ندارد.

سه سناریو، سه انتخاب: یک web service استاندارد که نیاز به رمزگذاری Basic Auth یا JWT دارد؟ از JDK استفاده کنید. پروژه قدیمی که از قبل Commons Codec را از طریق Spring یا Apache HTTP Client می‌کشد؟ از آن استفاده کنید — دلیلی برای داشتن دو کتابخانه Base64 در classpath وجود ندارد. پروژه‌ای که از Guava برای caching و collection استفاده می‌کند؟ از BaseEncoding برای API fluent تمیز آن استفاده کنید. هیچ‌گاه فقط برای رمزگذاری Base64 کتابخانه‌ای اضافه نکنید — نسخه JDK از سال ۲۰۱۴ به اندازه کافی خوب بوده است.

اگر نیاز دارید یک نتیجه رمزگذاری‌شده را سریعاً بدون اجرای کد Java تأیید کنید، آن را در Base64 Encoder paste کنید تا تأیید کنید که خروجی با آنچه کد شما تولید می‌کند مطابقت دارد.

سوالات متداول

چطور می‌توان یک String را در Java به Base64 رمزگذاری کرد؟

ابتدا رشته را با استفاده از getBytes(StandardCharsets.UTF_8) به بایت تبدیل کنید، سپس آرایه بایت را به Base64.getEncoder().encodeToString() بدهید. همیشه UTF-8 را به‌صراحت مشخص کنید — فراخوانی getBytes() بدون آرگومان charset از پیش‌فرض پلتفرم استفاده می‌کند که بین سیستم‌عامل‌ها و تنظیمات JVM متفاوت است.

Java
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String payload = "grant_type=client_credentials&scope=read:metrics";
String encoded = Base64.getEncoder()
    .encodeToString(payload.getBytes(StandardCharsets.UTF_8));
// Z3JhbnRfdHlwZT1jbGllbnRfY3JlZGVudGlhbHMmc2NvcGU9cmVhZDptZXRyaWNz

تفاوت Base64.getEncoder() و Base64.getUrlEncoder() چیست؟

هر دو به Base64 رمزگذاری می‌کنند، اما getUrlEncoder() از الفبای URL-safe تعریف‌شده در RFC 4648 بخش ۵ استفاده می‌کند. این متد + را با - و / را با _ جایگزین می‌کند تا خروجی بتواند در URL و نام فایل‌ها بدون percent-encoding ظاهر شود. رمزگذار استاندارد از + و / استفاده می‌کند که با پارامترهای query و بخش‌های path در URL تداخل دارند.

Java
byte[] data = "subject=usr_7b3c&role=admin".getBytes(StandardCharsets.UTF_8);

String standard = Base64.getEncoder().encodeToString(data);
// c3ViamVjdD11c3JfN2IzYyZyb2xlPWFkbWlu

String urlSafe = Base64.getUrlEncoder().encodeToString(data);
// c3ViamVjdD11c3JfN2IzYyZyb2xlPWFkbWlu
// (همین‌جا یکی است، اما اگر + یا / ظاهر شود → - یا _)

آیا java.util.Base64 در Java 8 و Java 17 یکسان است؟

بله. API کلاس java.util.Base64 از زمان معرفی در Java 8 تغییر نکرده است. کلاس، کلاس‌های تودرتوی Encoder و Decoder، و تمام متدهای factory (getEncoder، getUrlEncoder، getMimeEncoder) در Java 8، 11، 17 و 21 یکسان هستند. هنگام ارتقای نسخه JDK نیازی به migration یا تغییر کد نیست.

Java
// این کد روی Java 8 تا Java 21+ یکسان کامپایل و اجرا می‌شود
import java.util.Base64;
import java.nio.charset.StandardCharsets;

String encoded = Base64.getEncoder()
    .encodeToString("stable-api".getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);  // c3RhYmxlLWFwaQ==

چطور می‌توان یک فایل را در Java به Base64 رمزگذاری کرد؟

فایل را با Files.readAllBytes(Path) به آرایه بایت بخوانید و به Base64.getEncoder().encodeToString() بدهید. برای فایل‌های بزرگی که نباید کاملاً در حافظه بارگذاری شوند، از Base64.getEncoder().wrap(OutputStream) برای استریم کردن خروجی رمزگذاری‌شده استفاده کنید.

Java
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;

byte[] fileBytes = Files.readAllBytes(Path.of("config/tls-cert.pem"));
String encoded = Base64.getEncoder().encodeToString(fileBytes);

چرا sun.misc.BASE64Encoder منسوخ شد؟

sun.misc.BASE64Encoder یک کلاس داخلی JDK بود که هیچ‌گاه بخشی از API عمومی نبود. در بسته sun.misc قرار داشت که Oracle صراحتاً از استفاده از آن منع می‌کرد. Java 8 کلاس java.util.Base64 را به‌عنوان جایگزین رسمی، عمومی و پشتیبانی‌شده معرفی کرد. از Java 9 و سیستم ماژول، دسترسی به کلاس‌های sun.misc بسته به تنظیمات JDK هشدار یا خطا ایجاد می‌کند.

Java
// روش قدیمی — استفاده نکنید، در JDKهای مدرن حذف شده است
// import sun.misc.BASE64Encoder;
// String encoded = new BASE64Encoder().encode(data);

// روش صحیح از Java 8 به بعد
import java.util.Base64;
String encoded = Base64.getEncoder().encodeToString(data);

چطور می‌توان در Java یک round-trip رمزگذاری و رمزگشایی Base64 انجام داد؟

با Base64.getEncoder().encodeToString(bytes) رمزگذاری کنید و با Base64.getDecoder().decode(encodedString) رمزگشایی کنید. آرایه بایت رمزگشایی‌شده را با new String(bytes, StandardCharsets.UTF_8) به String تبدیل کنید. round-trip داده اصلی را کاملاً حفظ می‌کند — تا زمانی که از همان charset هم در getBytes() و هم در new String() استفاده کنید.

Java
import java.util.Base64;
import java.nio.charset.StandardCharsets;

// رمزگذاری
String original = "session_token=eyJhbGciOiJSUzI1NiJ9";
byte[] originalBytes = original.getBytes(StandardCharsets.UTF_8);
String encoded = Base64.getEncoder().encodeToString(originalBytes);

// رمزگشایی
byte[] decodedBytes = Base64.getDecoder().decode(encoded);
String decoded = new String(decodedBytes, StandardCharsets.UTF_8);

System.out.println(original.equals(decoded));  // true

ابزارهای مرتبط

  • Base64 Decoderرشته‌های Base64 را به متن یا داده باینری اصلی برگردانید — عملیات معکوس رمزگذاری.
  • URL Encoderرشته‌ها را برای استفاده امن در URL با percent-encoding رمزگذاری کنید — متفاوت از رمزگذاری URL-safe در Base64، اما اغلب کنارش استفاده می‌شود.
  • JWT Decoderتوکن‌های JWT که بخش‌های header و payload آن‌ها به‌صورت Base64url-encoded JSON هستند را بازرسی کنید — بدون نیاز به کتابخانه رمزگشایی کنید.
  • JSON Formatterپیلودهای JSON را قبل یا بعد از رمزگذاری Base64 زیبا چاپ کنید — مفید هنگام اشکال‌زدایی یکپارچه‌سازی‌های API.
AO
Aisha OseiJava Security & API Engineer

Aisha is a Java engineer specialising in application security, Spring Security, and API design. She has worked on identity and access management systems, OAuth 2.0 integrations, and microservice security at scale. She writes about secure Java coding practices, token validation, cryptographic utilities, and the Spring ecosystem from a security-first perspective.

PN
Pavel Novakبازبین فنی

Pavel is a backend engineer with deep roots in the JVM ecosystem, working primarily with Java and Kotlin. He has extensive experience building data-intensive services and integrating third-party APIs at scale. He writes about modern Java features, the Jackson ecosystem, serialisation patterns, and practical approaches to keeping large codebases maintainable.