क्या आपको Base64 फ़ॉर्मेट के साथ काम करना होता है? तो यह साइट आपके लिए एकदम सही है! अपने डेटा को एन्कोड या डिकोड करने के लिए, हमारे बेहद आसान ऑनलाइन टूल का इस्तेमाल करें।

Rust में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड

आप कुछ बाइट्स को सिर्फ़ टेक्स्ट वाले दरवाज़े से भेजने वाले हैं, और प्रवेश की कीमत एक स्ट्रिंग है - अक्षर, अंक, प्लस चिह्न और स्लैश की - जो आपके मूल से करीब एक-तिहाई लंबी है। स्वागत है Base64 में, इंटरनेट के टोल बूथ में। इस साइट का होम पेज इस फ़ॉर्मैट को पूरा-पूरा गहराई से समझाता है, इसलिए यहाँ बस शक्ल दोहरानी है: Base64 तीन इनपुट बाइट्स को 64-चिह्नों की वर्णमाला से लिए चार चरों के रूप में लिखता है, और पूंछ में एक या दो = चर पढ़ने वाले को बताते हैं कि असली डेटा कहाँ ख़त्म हुआ। वही चार-बदल-तीन सौदा इस फ़ॉर्मैट की पूरी अर्थव्यवस्था है, और यह गाइड Rust में इसे अच्छे तरह करने के बारे में है।

पहली बात यह जान लेना कि Rust की स्टैंडर्ड लाइब्रेरी आपके लिए यह काम नहीं करेगी। कोई base64_encode() नहीं है जो std में छिपा हो, और कोई use std::... भी नहीं जो आपका मन बदल दे। एकोसिस्टम ने बस एक ही क्रेट पर फैसला किया, जिसका नाम सिर्फ़ base64 है, और वह पूरे एकोसिस्टम की रीढ़ बन गया: वर्ज़न 0.23.1 4 अगस्त 2026 को रिलीज़ हुआ, दिसंबर 2015 से अब तक इस क्रेट ने 45 वर्ज़न पब्लिश किए हैं, और उसका डाउनलोड काउंटर 1.5 अरब के आसपास बैठा है। नीचे के हर एन्कोडिंग उदाहरण उसी एक क्रेट का इस्तेमाल करते हैं, साथ में लाइन रैपिंग और PEM कवच के लिए दो छोटे साथियों के।

टूलचेन और क्रेट

पहले टूलचेन, हर दुनिया के लिए एक कमांड:

# Debian / Ubuntu
sudo apt install rustc cargo
# या ऑफिशियल इंस्टॉलर, जो rustup और cargo सेटअप करता है
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

फिर क्रेट, किसी भी cargo प्रोजेक्ट के अंदर:

cargo new my-app
cd my-app
cargo add base64

वह एक ही लाइन पूरा इंस्टॉल है, और इससे बिल्कुल ज़ीरो डिपेंडेंसीज़ आती हैं। क्रेट के साथ तीन वैकल्पिक फ़ीचर्स आते हैं जो आपको जानने चाहिए: std (डिफ़ॉल्ट रूप से on; यह std::io स्ट्रीमिंग, स्टैंडर्ड Error इम्प्लीमेंटेशन और हीप अलोकेशन देता है), alloc (इम्बेडेड no_std बिल्ड्स के लिए अलोकेशन वाले APIs) और simd-unsafe (डिफ़ॉल्ट रूप से on; वे SIMD इंजन जो कुछ सेक्शन नीचे दिखते हैं)। कम से कम सपोर्टेड Rust वर्ज़न 1.71.0 है, इसलिए कोई भी हालिया वर्ज़न इसे चला लेगा। उसके चारों ओर उन कामों के साथी बैठे हैं जो मूल क्रेट जान-बूझ कर नहीं करता:

  • लाइन-रैप (वर्ज़न 0.2) 76 या 64 चरों की लाइन ब्रेक्स डालता है जो MIME और PEM माँगते हैं; base64 क्रेट खुद जान-बूझ कर रैप करने से इनकार करता है, जैसे आप देखेंगे।
  • pem (वर्ज़न 4) सर्टिफ़िकेट्स और कुंजीयों के लिए -----BEGIN ...----- ब्लॉक्स बनाता और पार्स करता है; यह अंदर से base64 पर निर्भर है और कवच और रैपिंग जोड़ता है।
  • base64ct (वर्ज़न 1.8) RustCrypto प्रोजेक्ट का कन्स्टेंट-टाइम डिकोडर है, तब के लिए जब राउंड ट्रिप का पढ़ने वाला हिस्सा ही संवेदनशील आधा है।
  • base64-turbo (वर्ज़न 0.3) एक नया हाई-थ्रूपुट कोडेक है जो मॉडर्न हार्डवेयर पर 100 GiB/s से ऊपर तक पहुँचता है।

एक एन्कोड, चार चर

सबसे छोटी संभव रस्म इस तरह दिखती है, और यह पहले से पूरा राउंड ट्रिप साबित कर चुकी है:

use base64::prelude::*;
fn main() {
  let packed = BASE64_STANDARD.encode("Hello, world!");
  println!("{packed}");
  // SGVsbG8sIHdvcmxkIQ==
  let back = BASE64_STANDARD.decode(packed).unwrap();
  println!("{}", String::from_utf8(back).unwrap());
  // Hello, world!
}

दो बातें नोट करने लायक हैं। prelude मॉड्यूल चुपचाप एक साथ दो चीज़ें सौंप देता है: BASE64_STANDARD इंजन और Engine ट्रेट, जिसके मेटोड्स आप कॉल कर रहे हैं - इसीलिए बस use base64::prelude::*; इस उदाहरण के लिए सब कुछ है। और encode() कुछ भी ले लेता है जिसे बाइट्स के रूप में पढ़ा जा सकता है, AsRef<[u8]> बॉउंड की वजह से: &str, &[u8] लिटरल, Vec<u8>, जो नाम आप लें। उदाहरण का डिकोडिंग वाला आधा हिस्सा बस एन्कोडर पर नज़र रखने के लिए है, क्योंकि उल्टी दिशा को sister साइट पर अपना पूरा गाइड मिलता है। अगर आप क्रेट का अपना स्मोक टेस्ट चाहते हैं, तो उसकी डॉक्यूमेंटेशन asdf को एन्कोड करती है और YXNkZg== वापस पाती है; वही वर्णमाला, वही गणित।

हर बाइट की बिल्कुल सही कीमत

अस्तित्व की हर Base64 एन्कोडर एक ही कर वसूलती है, और एक बार जब गणित दिखने लगे, तो उसके लिए बजट भी बना सकते हैं। हर आउटपुट चर 6 बिट्स के साथ आता है, हर इनपुट बाइट 8 के, और सबसे छोटा ढेर जो दोनों के गुणज हो 24 बिट्स है: बिल्कुल 3 बाइट्स अंदर, बिल्कुल 4 चर बाहर। वही अनुपात पूरा शो है, इसलिए 3 किलोबाइट की फ़ाइल 4 किलोबाइट बन जाती है और 10 मेगाबाइट का अपलोड 13.3। पैडिंग वह राउंडिंग एरर है जो दिखने लग जाए: जब इनपुट 3 बाइट्स का गुणज न हो, तो आख़िरी ग्रुप में खाली कैपासिटी बचती है, और एन्कोडर उसे = से भर देता है ताकि आउटपुट की लंबाई 4 का गुणज बनी रहे। यहाँ है RFC 4648 की सच टेबल, जिसे स्टैंडर्ड इंजन बिल्कुल सटीक रूप से दोहराता है:

इनपुट लंबाई mod 3 एन्कोडेड आउटपुट लंबाई
"" (खाली) 0 "" (खाली) 0
f 1 Zg== 4
fo 2 Zm8= 4
foo 0 Zm9v 4
foobar 0 Zm9vYmFy 8
use base64::prelude::*;
let words: [&[u8]; 4] = [b"", b"f", b"fo", b"foo"];
for input in words {
  println!("{:?} -> {:?}", String::from_utf8_lossy(input), BASE64_STANDARD.encode(input));
}
// "" -> ""
// "f" -> "Zg=="
// "fo" -> "Zm8="
// "foo" -> "Zm9v"

पहली पंक्ति दो बार पढ़िए, क्योंकि यही वह पंक्ति है जो हर किसी के दिमाग में ग़लत बैठती है: खाली इनपुट खाली स्ट्रिंग में एन्कोड होता है, AA== में नहीं। स्ट्रिंग AA== बिल्कुल एक बाइट - NUL - का एन्कोडिंग है, जो सच में अलग पेलोड है। और जब आपको एन्कोड करने से पहले बफ़र साइज़ तय करना हो, तो क्रेट गणित एक const fn के रूप में सौंपता है, इसलिए आप एरे को कंपाइल टाइम पर साइज़ भी कर सकते हैं:

let padded = base64::encoded_len(15, true).unwrap();
let slim = base64::encoded_len(15, false).unwrap();
println!("{padded} / {slim}");   // 20 / 20
println!("{:?}", base64::encoded_len(13, true));  // Some(20)
println!("{:?}", base64::encoded_len(13, false)); // Some(18)
println!("{:?}", base64::encoded_len(14, false)); // Some(19)
println!("{:?}", base64::encoded_len(100, false)); // Some(134)

13 और 14 बाइट्स वाली पंक्तियों पर नज़र रखिए, क्योंकि यही वह पंक्तियाँ हैं जो ऊँगली-गिनती वाली गणिति में फिसलाव लाती हैं: 13 बाइट्स को बिना पैडिंग 18 चर चाहिए लेकिन पैडेड 20, जबकि 14 बाइट्स को 19 और 20 चाहिए। फ़ंक्शन Option लौटाता है, जो None तभी होता है जब लंबाई की गणिति overflow हो जाए, इसलिए unwrap() हर उन इनपुट के लिए सुरक्षित है जो मेमोरी में सच में मौजूद हो सकते हैं। ईमेल-मंज़र वाले दुनिया के लिए इस कर पर एक सर्चार्ज है: MIME लाइन्स 76 चरों पर रैप करती है, और पुराना अनुभव-नियम कहता है कि रैप्ड Base64 की कीमत मूल आकार की लगभग 1.37 गुना होती है, साथ में हेडर ओवरहेड भी। क्रेट की अपनी FAQ की पैडिंग खुद के बारे में कम ही आदबी भरी राय है: = बाइट्स "डिकोडिंग पर बस इतना असर करते हैं कि यह मौक़ा मिलता है, 'वह पैडिंग ग़लत है' कहने का", और "बिना शक exabytes स्टोरेज और ट्रांसफ़र बेकार = बाइट्स पर बर्बाद हुए होंगे"।

पैडिंग: पढ़ने वाले के बारे में फैसला

base64 0.23 में साधारण एन्कोड फ़ंक्शन्स डेप्रिकेटेड हो गए हैं - अब की राह है Engine पर कोई मेटोड कॉल करना, और इंजन एक नीति है: कौन-सी वर्णमाला लिखनी है, और कौन-सी पैडिंग जोड़नी है। प्रीसेट्स base64::engine::general_purpose में रहते हैं, और चार लोकप्रिय को prelude में पुनः-एक्सपोर्ट किया गया है:

इंजन वर्णमाला पैडिंग जोड़ता है इसके लिए सर्वोत्तम
STANDARD / BASE64_STANDARD + / हाँ सब कुछ, डिफ़ॉल्ट
STANDARD_NO_PAD / BASE64_STANDARD_NO_PAD + / नहीं सिक पेलोड्स जो आप ख़ुद भी इस्तेमाल करते हैं
URL_SAFE / BASE64_URL_SAFE - _ हाँ URL कंटेंट जो अब भी पैडिंग चाहता है
URL_SAFE_NO_PAD / BASE64_URL_SAFE_NO_PAD - _ नहीं JWTs, URLs, ऑब्जेक्ट IDs

बिना पैडिंग एन्कोडिंग कोई चाल नहीं है जो क्रेट सह ले; यह फ़र्स्ट-क्लास पोज़िशन है, प्रीकॉन्फिगर्ड NO_PAD और PAD कॉन्फ़िग कॉन्स्टेंट्स के साथ, साथ में 0.23.0 में जुड़े *_INDIFFERENT भाइयों के। अगर प्रीसेट्स फिट न हों, तो आप Alphabet और GeneralPurposeConfig से, एक डायल के साथ, अपना इंजन बना लेते हैं, और क्योंकि इंजन बनाना सस्ता है, आप नतीजे को const में स्टोर करते हैं, हर रिक्वेस्ट पर दोबारा बनाने के बजाय:

use base64::engine::general_purpose::{GeneralPurpose, GeneralPurposeConfig};
use base64::prelude::*;
const SLIM: GeneralPurpose = GeneralPurpose::new(
  &base64::alphabet::STANDARD,
  GeneralPurposeConfig::new().with_encode_padding(false),
);
fn main() {
  println!("{}", SLIM.encode("fo"));   // Zm8
  println!("{}", BASE64_STANDARD.encode("fo")); // Zm8=
}

अब फैसला दूसरों के डिकोडरों के बारे में फैसला बन जाता है, जो कभी भी बस सौंदर्य का सवाल नहीं होता। डिकोड साइड की सख़्ताई के नियम DecodePaddingMode से आते हैं, और नीचे की टेबल का जवाब है: "क्या दूसरी तरफ़ वह पढ़ लेगी जो मैंने लिखा?":

आप किससे एन्कोड करते हैं सख़्त STANDARD डिकोडर STANDARD_NO_PAD डिकोडर INDIFFERENT डिकोडर
STANDARD (पैडेड) पढ़ लेता है = ठुकरा देता है पढ़ लेता है
STANDARD_NO_PAD ठुकरा: पैडिंग मिसिंग पढ़ लेता है पढ़ लेता है
URL_SAFE_NO_PAD ठुकरा: ग़लत वर्णमाला ठुकरा: ग़लत वर्णमाला बस URL वर्णमाला के साथ पढ़ता है

प्रैक्टिकल नियम उस टेबल से निकलते हैं। अगर आप दोनों सिरे संभालते हैं, तो एक इंजन चुनिए और हर जगह इस्तेमाल कीजिए, और बाइट्स बचाने के लिए बिना पैडिंग को ही पसंद कीजिए। अगर आप बाहर की दुनिया का डेटा खपत करते हैं, तो आपके डिकोडर को इसमें वोट का हक़ है कि आपको कौन-सा इंजन निकालना चाहिए: स्टॉक STANDARD डिकोडर को आपकी पैडिंग चाहिए, जबकि STANDARD_PAD_INDIFFERENT डिकोडर दोनों मान लेता है। और इस चुनाव में सुरक्षा का स्वाद भी है। एक ही पेलोड की पैडेड और बिना पैडिंग दोनों स्पेलिंग्स की इजाज़त Base64 को लचीला बना देती है; 2022 का पेपर "अमल में Base64 की लचिली" (Chatzigiannis और Chalkias, ePrint 2022/361), जिसे क्रेट की अपनी डॉक्यूमेंटेशन लिंक करती है, दिखाता है कि क्यों। उस प्रोटोकॉल में जहाँ वही डेटा दो अलग तरह से लिखा जा सके, उसकी आदत होती है कि वह कोड को चौंका दे जो एन्कोडेड स्ट्रिंग को पहचान मानती है, इसलिए जब आपका फ़ॉर्मैट एक कैनोनिकल स्पेलिंग तय करता है, तो उसे बाउंडरी पर लागू कीजिए।

Tokens और लिंक के लिए Base64url

स्टैंडर्ड Base64 के वर्णमाला के अंतिम दो अक्षर + और / हैं, और URL में ये उस भाषा के दो सबसे महँगे चर हैं: प्लस बन जाता है %2B, स्लैश बन जाता है %2F, और पैडिंग बन जाती है %3D। RFC 4648 सेक्शन 5 इसे URL- और फ़ाइलनेम-सुरक्षित वर्णमाला से ठीक करता है, जो दो मुसीबतख़ोरों को - और _ से बदल देता है और आमतौर पर पैडिंग को भी छोड़ कर देता है। इंजन इस अंतर को बिल्कुल छुपाने नहीं देते:

use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use base64::Engine;
let packed = URL_SAFE_NO_PAD.encode(b"\xfb\xef\xbe");
println!("{packed}");          // ----
let back = URL_SAFE_NO_PAD.decode(packed).unwrap();
println!("{back:02x?}");       // [fb, ef, be]

सबसे ख़राब संभावित इनपुट के तीन बाइट्स एक चार-चरों की स्ट्रिंग बन जाते हैं, जिसे आप बिना किसी परसेंट एस्केप के URL, फ़ाइलनेम, कुकी या डेटाबेस कुंजी में पेस्ट कर सकते हैं। यही वह वर्णमाला है जिसमें JSON Web Tokens रहते हैं: JWT तीन base64url हिस्से हैं जो बिंदुओं से जुड़े होते हैं, और jsonwebtoken क्रेट (2026 में वर्ज़न 11) से एक बनाना इस तरह दिखता है:

use serde::Serialize;
use jsonwebtoken::{EncodingKey, Header, encode};
#[derive(Debug, Serialize)]
struct Claims {
  sub: String,
  company: String,
  exp: u64,
}
let key = b"secret";
let my_claims = Claims {
  sub: "b@b.com".to_owned(),
  company: "ACME".to_owned(),
  exp: 19_000_000_000,  // भविष्य में क़ाफ़ी आगे
};
let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret(key)).unwrap();
println!("{token}");
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJiQGIuY29t...

वर्ज़न 11 में एक सेटअप रिक्वायरमेंट है जो नए लोगों को टिंचाता है: क्रेट को rust_crypto या aws_lc_rs फ़ीचर्स में से बिल्कुल एक का on होना चाहिए Cargo.toml में, और अगर कोई भी on न हो तो पहली बार टोकन साइन या वैरिफ़ाई करते ही वह पैनिक कर जाएगा। struct में exp क्लेम पर नज़र रखिए: क्रेट की वैलिडेशन इसे डिफ़ॉल्ट रूप में ज़रूरी मानती है, इसलिए असली टोकन में वह आख़िरकार रहता ही है, और टोकन की base64url वर्णमाला पूरी तरह लाइब्रेरी की अपनी बात है। अगर आप टोकन बनाने की बजाय बस उन्हें जाँच रहे हैं, तो sister लेख पाँच पंक्तियों वाला झाँकना दिखाता है। और सुनहरे नियम की एक याद दिलाई, जो टोकन पर विशेष ताकत से लागू होती है: JWT के तीनों हिस्से कुंजी के बिना पढ़े जा सकते हैं। Base64 खिड़की वाली सीट है, लॉक नहीं।

टेक्स्ट अंदर, बाइट्स बाहर

एन्कोडर मन नहीं पढ़ते, इसलिए Rust में "इस स्ट्रिंग को एन्कोड करो" हमेशा "इस स्ट्रिंग के UTF-8 बाइट्स को एन्कोड करो" का मतलब रखता है, क्योंकि बस यही str::as_bytes() सौंपता है। अच्छी ख़बर यह है कि आधुनिक वेब लगभग पूरी तरह UTF-8 है, इसलिए ईमानदार रास्ता छोटा और ख़ुशनुमा है:

use base64::prelude::*;
let text = "café";
let packed = BASE64_STANDARD.encode(text.as_bytes());
println!("{packed}");   // Y2Fmw6k=

मल्टीबाइट वाले केस सब सही तरह से व्यवहार करती हैं:

मूल टेक्स्ट Base64 राउंड ट्रिप
café Y2Fmw6k= साफ़
日本語 5pel5pys6Kqe साफ़
😀 8J+YgA== साफ़
π ≈ 3.14159 z4Ag4omIIDMuMTQxNTk= साफ़

एकमात्र असली फैसला यह है कि आप किन बाइट्स से शुरू करते हैं। अगर डेटा टेक्स्ट के बजाय बाइट्स के रूप में आया है, डिस्क से पढ़ी गई फ़ाइल या नेटवर्क कॉल से आया बफ़र, तो स्ट्रिंग को बिल्कुल छोड़ कर दीजिए और Vec<u8> को सीधे एन्कोड कीजिए; यह PNG या protobuf जैसे नॉन-UTF-8 पेलोड्स के लिए भी एकमात्र सही जवाब है। अपने कोड के बगल में कोई भी इमेज रख दीजिए और read को उसकी तरफ़ इशारा कीजिए:

use base64::prelude::*;
let file_bytes = std::fs::read("sprite.png").unwrap();
let size = file_bytes.len();
let packed = BASE64_STANDARD.encode(file_bytes);
println!("{size} bytes -> {} base64 chars", packed.len());
// हर encoded PNG iVBORw0K से शुरू होता है
assert!(packed.starts_with("iVBORw0K"));

वह आख़िरी assertion एक मुफ़्त सेनिटी चेक है और इंटरनेट के सबसे पहचाने जाने वाले प्रीफिक्स में से एक। और अगर आप कभी भी वही लॉजिकल टेक्स्ट दो अलग कैरेक्टर सेट्स के रास्ते एन्कोड करें, या उन बाइट्स को एन्कोड करें जो आपने ग़लत कैरेक्टर सेट के रूप में पढ़ लिया, तो राउंड ट्रिप सीधा चेहरा बनाकर mojibake के रूप में लौटेगा। एन्कोडर कभी झूठ नहीं बोलता; वह बस आपसे जो बाइट्स मिले वही एन्कोड कर देता है, जो इसकी सबसे बड़ी ताकत है और इसकी एकमात्र चाल भी।

जब फ़ॉर्मैट को लाइन्स चाहिए

base64 क्रेट जान-बूझ कर लाइन ब्रेक्स नहीं डालता, और यह पहली बार नहीं है जब उसने वह फैसला किया। वर्ज़न 0.5.0 बिल्ट-इन MIME लाइन रैपिंग के साथ रिलीज़ हुआ, कॉन्फ़िगर करने लायक लाइन एंडिंग्स के साथ, और वर्ज़न 0.10.0 ने उसे हटा दिया, लाइब्रेरी का फैसला था कि रैपिंग किसी जनरल क्रेट के लिए ज़्यादा राय-खास थी और no_std की कहानी मुश्किल बना देती थी। अगर फ़ॉर्मैट को लाइन्स चाहिए, तो line-wrap क्रेट बस इसके लिए मौजूद है। उसका एकमात्र फ़ंक्शन, line_wrap(), आपका प्री-अलोकेटेड बफ़र, इनपुट की लंबाई, कॉलम लिमिट और लाइन एंडिंग लेता है, और लौटाता है कि उसने कितने लाइन-एंडिंग बाइट्स डाले:

use base64::prelude::*;
let data = BASE64_STANDARD.encode(vec![b'a'; 300]);  // 400 चर
let mut buf = vec![0u8; data.len() + 16];
buf[..data.len()].copy_from_slice(data.as_bytes());
let endings = line_wrap::line_wrap(&mut buf, data.len(), 76, &line_wrap::crlf());
buf.truncate(data.len() + endings);
let wrapped = String::from_utf8(buf).unwrap();
println!("{} chars in, {} bytes out, {} line endings", data.len(), wrapped.len(), endings);
// 400 चर अंदर, 410 बाइट्स बाहर, 10 लाइन एंडिंग्स (पाँच CRLF जोड़ी)

बफ़र को एंडिंग्स के लिए जगह के साथ आगे-से साइज़ कीजिए, फ़ंक्शन कॉल कीजिए, और रिपोर्टेड कुल तक truncate कीजिए; पाँच CRLF जोड़ियाँ MIME की 76-कॉलम नियम की कीमत हैं। PEM के लिए लिमिट और एंडिंग बदल दीजिए, 64 कॉलम्स और line_wrap::lf(), और कवच की बॉडी टेक्स्ट तैयार है। फिर pem क्रेट एक कॉल में बैनर्स जोड़ देता है:

let pem_block = pem::encode(&pem::Pem::new("CERTIFICATE", b"0123456789abcdef"));
println!("{pem_block}");
// -----BEGIN CERTIFICATE-----
// MDEyMzQ1Njc4OWFiY2RlZg==
// -----END CERTIFICATE-----
let back = pem::parse(pem_block).unwrap();
println!("{}: {} bytes", back.tag(), back.contents().len());
// CERTIFICATE: 16 bytes
// और Unix-स्टाइल लाइन एंडिंग्स, अगर consumer चुनेबाज़ हो
let lf_block = pem::encode_config(
  &pem::Pem::new("KEY", b"0123456789abcdef"),
  pem::EncodeConfig::new().set_line_ending(pem::LineEnding::LF),
);

डिफ़ॉल्ट रूप से, pem::encode CRLF इस्तेमाल करता है, PEM का ऐतिहासिक कन्वेंशन; set_line_ending बिल्डर उन टूल्स के लिए LF पर स्विच करता है जो उसे उम्मीद करते हैं। नोट कीजिए कि pem क्रेट क्या नहीं करता: वह कभी भी कोई ऐसा base64 फ़ंक्शन कॉल नहीं करता जिसे आप देख सकें, क्योंकि एन्कोडिंग उसकी अंदरूनी बात है। जब फ़ॉर्मैट को लाइन्स चाहिए, तो आर्किटेक्चर है एक काम पर एक क्रेट।

कन्स्टेंट स्पेस में स्ट्रीमिंग

उन डेटा के लिए जो एक वेरिएबल में थामे नहीं रखे जा सकते, क्रेट बाक़ी Rust io जैसी ही स्ट्रीमिंग फिलसोफी से जवाब देता है: write::EncoderWriter किसी भी राइटर को रैप करता है और कन्स्टेंट स्पेस में, आपका जो कुछ भी लिखते हैं, सब base64-एन्कोड कर देता है। बफ़र के लिए पूरा अनुष्ठान इस तरह दिखता है, और इस सेक्शन का सितारा finish() कॉल है:

use std::io::Write;
use base64::prelude::*;
use base64::write::EncoderWriter;
fn main() {
  let mut encoder = EncoderWriter::new(Vec::new(), &BASE64_STANDARD);
  encoder.write_all(b"the quick brown fox jumps over the lazy dog").unwrap();
  let packed = encoder.finish().unwrap();
  println!("{}", String::from_utf8(packed).unwrap());
  // dGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==
}

finish() सितारा क्यों है? क्योंकि बस यही वह कॉल है जो आख़िरी अधूरा ग्रुप को फ़्लश करती है और पैडिंग जोड़ती है, और एन्कोडर के पास एक समकक्ष मेटोड है जो ऐसा नहीं करता। क्रेट की अपनी डॉक्यूमेंटेशन इसे सीधा कहती है: finish() "बाकी बचे इनपुट बाइट्स को एन्कोड करती है और जहाँ ज़रूरी हो वहाँ पैडिंग जोड़ती है। drop होने पर वह अपने-आप कॉल हो जाती है (Drop इम्प्लीमेंटेशन देखिए), लेकिन नीचे वाले राइटर को कॉल करते समय जो कोई भी एरर हो जाए, वह दबा दिया जाता है। अगर आप ऐसे एरर्स को हँडल करना चाहते हैं, तो finish() ख़ुद कॉल कीजिए।" Drop इम्प्लीमेंटेशन BufWriter की तरह व्यवहार करता है: वह फ़्लश करता है, लेकिन drop के दौरान एरर्स को अनदेखा करता है। तो आख़िरी अधूरा ग्रुप खो नहीं जाता, लेकिन "शायद काम आया है" कोई शिपिंग स्ट्रैटेजी नहीं है, क्योंकि वह write एरर जो वह आपको बता सकता था, गायब हो चुका है।

वही स्ट्रीम एक स्तर दूर, io::copy के रास्ते भी काम करती है, जब आप पूरा पाइपलाइन एक कॉल में चाहें, और "बस इसे फ़ॉर्मैट स्ट्रिंग के अंदर चाहिए" वाले मोमेंट्स के लिए एक बोनस रैपर भी है:

use std::io;
use base64::prelude::*;
use base64::write::EncoderWriter;
let file = b"the quick brown fox jumps over the lazy dog".to_vec();
let mut cursor = io::Cursor::new(file);
let mut encoder = EncoderWriter::new(Vec::new(), &BASE64_STANDARD);
io::copy(&mut cursor, &mut encoder).unwrap();
let packed = encoder.finish().unwrap();
println!("{}", String::from_utf8(packed).unwrap());
use base64::display::Base64Display;
use base64::prelude::*;
let value = Base64Display::new(b"\0\x01\x02\x03", &BASE64_STANDARD);
println!("base64: {value}");   // base64: AAECAw==

वह Base64Display रैपर एक छोटा जवाहरात है: यह बिना एक ही हीप अलोकेशन के, किसी भी फ़ॉर्मैट स्ट्रिंग के अंदर बाइट्स को Base64 के रूप में फ़ॉर्मैट कर देता है, जिससे log लाइन्स और डीबग आउटपुट अचानक खुशनुमा बन जाते हैं।

अलोकेशन, और उसका अभाव

सुविधाजनक मेटोड अलोकेशन करता है, और ज़िंदगी के ज़्यादातर हिस्से के लिए वह सही सौदा है। लेकिन Engine ट्रेट एन्कोड के तीन रूप दिखाता है, और नीचे की टेबल पूरा निर्णय मैट्रिक्स है:

मेटोड आउटपुट अलोकेशन करता है
encode() नया String हमेशा
encode_string() आपके String में जोड़ देता है बस तभी जब उसे बढ़ना पड़े
encode_slice() आपके &[u8] में लिखता है कभी नहीं
use base64::prelude::*;
let input = b"Hello, world!";
let mut buf = vec![0u8; base64::encoded_len(input.len(), true).unwrap()];
let written = BASE64_STANDARD.encode_slice(input, &mut buf).unwrap();
buf.truncate(written);
println!("{}", std::str::from_utf8(&buf).unwrap());   // SGVsbG8sIHdvcmxkIQ==
// या बफ़र को पूरी तरह stack पर रखिए
let mut stack = [0u8; 24];
let n = BASE64_STANDARD.encode_slice(b"abc 123", &mut stack).unwrap();
println!("{}", String::from_utf8(stack[..n].to_vec()).unwrap());  // YWJjIDEyMw==
// और अगर आपने साइज़ ग़लत किया, तो आपको एरर मिलेगा, बफ़र overflow नहीं
let mut tiny = [0u8; 5];
println!("{:?}", BASE64_STANDARD.encode_slice(input, &mut tiny));
// Err(OutputSliceTooSmall)

बफ़र को encoded_len() से साइज़ कीजिए, encode_slice() से लिखिए, और अगर आपने साइज़ ग़लत पकड़ी तो आपको undefined व्यवहार के बजाय साफ़ EncodeSliceError::OutputSliceTooSmall मिलता है, जो सिस्टम्स भाषा में 'एक बोरिंग दोपहर' और 'एक लंबी शाम' का फ़र्क़ है। इम्बेडेड काम के लिए वही फ़ंक्शन्स alloc फीचर के पीछे मौजूद हैं, इसलिए आप API बनाए रख सकते हैं और हीप गिरा सकते हैं।

स्पीड: SIMD इंजन

वर्ज़न 0.23.0, जो जुलाई 2026 में रिलीज़ हुआ, मुख्य फीचर लेकर आया: स्टैंडर्ड और URL-सुरक्षित वर्णमालाओं के लिए SIMD से त्वरित इंजन। ये तीन हैं, और वे यह देखकर बँटते हैं कि वे आपकी हार्डवेयर पर कितना भरोसा करते हैं:

इंजन runtime पर डिटेक्ट करता है no_std में चलता है
Simd हाँ, AVX2 या NEON चुनता है, वरना scalar इंजन पर फ़ॉलबैक नहीं, डिटेक्शन के लिए std चाहिए
Avx2 नहीं, मानता है कि CPU में AVX2 है हाँ, x86_64 targets पर
Neon नहीं, मानता है कि CPU में NEON है हाँ, aarch64 targets पर
use base64::engine::general_purpose::GeneralPurposeConfig;
use base64::engine::{Avx2, Simd};
use base64::Engine;
let turbo = Simd::standard(GeneralPurposeConfig::new());
println!("{}", turbo.encode("simd works!"));
// c2ltZCB3b3JrcyE=
if let Some(fixed) = Avx2::standard(GeneralPurposeConfig::new()) {
  println!("{}", fixed.encode("hello avx2"));  // aGVsbG8gYXZ4Mg==
}

Simd कंस्ट्रक्टर अपना CPU डिटेक्शन एक बार करता है और जो सबसे अच्छा कर्नेल मिले वह लौटाता है, या अगर कोई लागू न हो तो scalar इंजन, इसलिए इसे एक बार const में या startup पर बना लें और दोबारा इस्तेमाल करें; सक्षम हार्डवेयर पर यह एन्कोडिंग और डिकोडिंग दोनों में scalar पाथ से कई गुना तेज़ है। एक ईमानदार फुटनोट: SIMD पाथ क्रेट में वही एक जगह है जो unsafe को छूती है, और इसीलिए इस फीचर का नाम simd-unsafe है। फीचर बंद कीजिए और पूरा क्रेट फिर #![forbid(unsafe_code)] हो जाता है, scalar इंजन अब भी ईमानदार काम करता हुआ। अगर रॉ थ्रूपुट ही पूरा मक़सद है, तो base64-turbo क्रेट लिफाफ़ा और आगे धकेलता है, runtime डिटेक्शन के पीछे AVX512, AVX2 और NEON कर्नेल के साथ 100 GiB/s से ऊपर तक, और बाक़ी सब पर 100% सुरक्षित scalar फ़ॉलबैक। base64 क्रेट ड्यूल-लाइसेंस्ड है MIT/Apache-2.0, तो यह सब मुफ़्त है, स्पीड समेत।

चार और वर्णमालाएँ

RFC की वर्णमाला डिफ़ॉल्ट है, लेकिन base64 क्रेट चार और साथ देता है, हर एक किसी असली प्रोटोकॉल का छोटा सा स्मारक है जिसने अपना खुद का मोड़ माँगा:

वर्णमाला मोड़ यह कौन इस्तेमाल करता है abc 123 इनमें एन्कोड होता है
alphabet::CRYPT ./ पहले, फिर अंक और अक्षर, बिना पैडिंग क्लासिक Unix crypt(3) पासवर्ड हैश MK7X612mAk
alphabet::BCRYPT ./ पहले, फिर अक्षर, फिर अंक bcrypt पासवर्ड हैश WUHhGBCwKu
alphabet::IMAP_MUTF7 कॉमा स्लैश की जगह खड़ी है, बिना पैडिंग IMAP के modified UTF-7 मैलबॉक्स नाम YWJjIDEyMw
alphabet::BIN_HEX पंक्चुएशन से भरपूर वर्णमाला जो पड़ने में मिलती-जुलती अक्षरों को छोड़ देती है BinHex 4, पुराना Macintosh फ़ाइल रैपर B@*M)$%b-`
use base64::engine::general_purpose::{GeneralPurpose, NO_PAD};
use base64::Engine;
let crypt = GeneralPurpose::new(&base64::alphabet::CRYPT, NO_PAD);
println!("{}", crypt.encode(b"abc 123"));   // MK7X612mAk
let bcrypt = GeneralPurpose::new(&base64::alphabet::BCRYPT, NO_PAD);
println!("{}", bcrypt.encode(b"abc 123"));  // WUHhGBCwKu
let imap = GeneralPurpose::new(&base64::alphabet::IMAP_MUTF7, NO_PAD);
println!("{}", imap.encode(b"abc 123"));    // YWJjIDEyMw

वही इनपुट, तीन अलग आउटपुट्स, तीनों अपनी-अपनी डायलैक्ट में वैध Base64। crypt वर्णमाला वही है जिसमें असली सुपरपावर है: क्योंकि इसके चिह्नों का क्रम बिट पैटर्न्स से मेल खाता है, एन्कोडेड स्ट्रिंग्स को सॉर्ट करने से वही क्रम मिलता है जो मूल बाइट्स को सॉर्ट करने से मिलता है, इसीलिए GEDCOM 5.5 (1996) ने मल्टीमीडिया फील्ड्स के लिए इसका इस्तेमाल किया - 5.5.1 रिवीज़न ने वह फीचर गिरा दिया - और क्रेट आज भी वह वर्णमाला आपके लिए साथ देता है। और अगर वह डायलैक्ट जो आपको चाहिए क्रेट में नहीं है, तो आप 64-चरों की स्ट्रिंग से उसे डिफ़ाइन कर सकते हैं, क्योंकि Alphabet::new() एन्कोड और डिकोड की टेबल्स आपके लिए बना देता है:

use base64::alphabet::Alphabet;
use base64::engine::general_purpose::{GeneralPurpose, PAD};
use base64::Engine;
// bizarro दुनिया वाला base64: +/ आख़िर में बजाय शुरू में
let alphabet = Alphabet::new(
  "+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
).expect("a valid 64 char alphabet");
let bizarro = GeneralPurpose::new(&alphabet, PAD);
println!("{}", bizarro.encode(b"hello 99"));  // YETqZE6eMRi=
// जबकि स्टैंडर्ड इंजन कहता है:
println!("{}", base64::prelude::BASE64_STANDARD.encode(b"hello 99"));
// aGVsbG8gOTk=

कस्टम वर्णमाला रास्ते के बारे में एक चेतावनी: जिस पल आप कोई नया डायलैक्ट जन्म देते हैं, आप पृथ्वी पर वही एक इंसान बन जाते हैं जो आपका डेटा पढ़ सकता है, इसलिए बस तभी कीजिए जब प्रोटोकॉल माँगता हो, और एक कमेंट लिखिए कि कौन-सा।

एन्कोडर कहाँ काम करते हैं

Base64 एन्कोडिंग Rust प्रोजेक्ट्स में कुछ तय मामलों में दिखता है:

  • JSON APIs में फ़ाइल अपलोड्स, जहाँ फ़ाइल टेक्स्ट के कपड़ों में लपटी बाइट फील्ड है, बहुत बड़े फ़ासले से सबसे आम उपयोग।
  • Data URIs HTML और CSS में, data:image/png;base64,... वाली किस्म, छोटे-मोटे इकोन्स के लिए शानदार, हेरो इमेजेस के लिए सवालिया निशान।
  • JWTs और OAuth, जहाँ base64url डायलैक्ट है और jsonwebtoken क्रेट औज़ार।
  • सर्टिफ़िकेट्स और कुंजीयों के लिए PEM ब्लॉक्स, -----BEGIN CERTIFICATE----- वाले सेक्शन जो Base64 को हर लाइन 64 चरों पर रैप करते हैं।
  • XML और कॉन्फ़िग फ़ाइलों में बायनेरी, <data encoding="base64"> वाला पैटर्न जो आज भी एक्सपोर्टेड बुकमार्क्स और सेटिंग्स डम्प्स में मिलता है।
  • LDAP और LDIF फ़ाइलें, जो बायनेरी एट्रिब्यूट वैल्यूज़ को एक ही लाइन पर रखने के लिए Base64 इस्तेमाल करते हैं।
  • QR कोड पेलोड्स और क्लिपबोर्ड हैंडऑफ़्स, जहाँ टेक्स्ट सफ़र से बचकर निकलता है, बायनेरी नहीं।
  • HTTP Basic ऑथ हेडर्स, जहाँ Basic TWFuOnBhc3M= एक क्रेडेंशियल पैर है, और एक याद दिलाई कि यह पैकिंग का सवाल है, छिपाने का नहीं।

और वही सुनहरा नियम जो सब पर राज करता है: Base64 पैकिंग टेप है, लॉक नहीं। यह एनक्रिप्शन नहीं है और कंप्रेशन नहीं है - यह कंप्रेशन का उल्टा है - और यह लेख पढ़ने वाला कोई भी एक लाइन में इसके हर काम को पलट सकता है। बिना झिझक एन्कोड कीजिए, लेकिन कभी भी पासवर्ड, API कुंजी या सीक्रेट को एन्कोड करके उसे सुरक्षित मत समझिए। अगर छुपाना ही है, तो असली एनक्रिप्शन इस्तेमाल कीजिए, और अगर वह बड़ा है, तो सोचिए कि क्या multipart अपलोड उस कर से बस सस्ता नहीं होता था।

छोटे-छोटे कदमों का दशक

फ़ॉर्मेट वेब से पुराना है। 1987 में Privacy-Enhanced Mail प्रोटोकॉल (RFC 989) को 7-बिट मेल चैनल्स पर बायनेरी डेटा ले जाने की ज़रूरत थी, और उसने इस एन्कोडिंग को बिल्कुल 64-चरों की लाइन्स के साथ स्टैंडरडाइज़ किया। इंटरनेट का जो भी -----BEGIN CERTIFICATE----- ब्लॉक है, वह उस फैसले का वंशज है, और इसीलिए PEM फ़ाइलें आज भी 64 पर रैप होती हैं। 1996 में MIME स्पेक (RFC 2045) ने स्कीम को अपन लिया, इसे उसके 64-चरों की वर्णमाला के नाम पर "base64" कहा, और रैप को 76 चरों पर ले आया। उससे पहले, Unix बॉक्स uuencode के साथ आते थे और Macs BinHex के साथ, हर एक की अपनी वर्णमाला, और दोनों आज भी पुराने सिस्टम्स में फ़ाइल हेडर्स के साथ जीवाश्मों की तरह सतह पर आते हैं। 2006 में RFC 4648 वह स्टैंडर्ड बन गया जिसे सब क्वोट करते हैं: वर्णमाला की टेबल्स, base64url वेरिएंट, और कैनोनिकल एन्कोडिंग के नियम जिनका इम्प्लीमेंट इस लेख का हर इंजन करता है। उसका सेक्शन 3.5 एन्कोडर को अन्यूस्ड ट्रेलिंग बिट्स को ज़ीरो करने को कहता है, और क्रेट वही करता है; अगर आपका पेलोड बाद में किसी सख़्त डिकोडर के InvalidLastSymbol चेक में फँसे, तो ख़राबी upstream हुई थी।

क्रेट का अपना इतिहास भी उसी ताल में चलता है। वह दिसंबर 2015 में crates.io पर दिखा, और वर्ज़न 0.5.0 ने गर्व से MIME लाइन रैपिंग जोड़ी, कॉन्फ़िगर करने लायक लाइन एंडिंग्स के साथ। फिर 2018 में वर्ज़न 0.10.0 ने रैपिंग और व्हाइटस्पेस हैंडलिंग हटा दी, लाइब्रेरी का फैसला था कि सामान्य-उद्देश्यीय क्रेट को एन्कोड करना चाहिए और कविता ऐप्लिकेशन लेयर को छोड़नी चाहिए; वही रिलीज़ स्ट्रीमिंग EncoderWriter भी जोड़ता है। 2022 में वर्ज़न 0.20.0 ने इंजन अब्स्ट्रैक्शन पेश किया और कैनोनिकल पैडिंग को डिफ़ॉल्ट बना दिया, और 0.21.0 ने इंजन मेटोड्स के पक्ष में पुराने फ्री फ़ंक्शन्स को डेप्रिकेटेड कर दिया, कंपाइलर नोट "Use Engine::encode" के साथ (वे अब भी चलते हैं, और इसीलिए बहुत सा लेगासी कोड ख़ुशी-ख़ुशी कंपाइल होता है)। 2024 में वर्ज़न 0.22.0 ने एरर सेमेंटिक्स को साफ़ किया और डिकोडिंग को 5 से 10 प्रतिशत तेज़ किया। और जुलाई 2026 में वर्ज़न 0.23.0 SIMD इंजनों, कस्टम पैडिंग चिह्नों, साफ़ एरर मैसेज और 1.71 तक MSRV बढ़ाकर आया, और 4 अगस्त के 0.23.1 पैच ने नॉन-SIMD आर्किटेक्चर्स के लिए टेस्ट स्यूट ठीक किया।

जिन बातों पर मुस्कुराया जाए

क्योंकि एक पूरा गाइड मुस्कान पर ख़त्म होना चाहिए:

  • शब्द "base64" का एन्कोड YmFzZTY0 होता है। खुद को डिस्क्राइब करता हुआ फ़ॉर्मैट बस मोर्स में बोलने वाले आइने का तकनीकी संस्करण है।
  • खाली स्ट्रिंग खाली स्ट्रिंग में एन्कोड होती है। "कुछ नहीं" ही वही एक इनपुट है जो कुछ भी नहीं लेता, जो एक तरह का कर-मुक्त है।
  • AA== "कुछ नहीं" का एन्कोडिंग नहीं है; यह एक NUL बाइट का एन्कोडिंग है। Base64 में "कुछ नहीं" और "एक ज़ीरो" अलग-अलग जीव हैं, और डिकोडर उन्हें अलग पहचान लेते हैं।
  • हर Base64-एन्कोडेड PNG iVBORw0K से शुरू होती है। वह PNG मैजिक नंबर है अपनी पैकिंग टेप में, इंटरनेट के सबसे पहचाने जाने वाले प्रीफिक्स में से एक।
  • URL में, स्टैंडर्ड Base64 चरों को एस्केप के कपड़े पहनने पड़ते हैं: प्लस बन जाता है %2B, स्लैश बन जाता है %2F, और पैडिंग बन जाती है %3D। Base64url इसलिए मौजूद है ताकि चर अपना ही चेहरा पहन सकें।
  • YouTube वीडियो IDs बिना पैडिंग वाला base64url हैं: ID के आठ बाइट्स उस 11-चरों की स्ट्रिंग बन जाते हैं जिसे आप कहीं भी पेस्ट कर सकते हैं। पूरे इंटरनेट पर बिना पैडिंग वाले मोड के सबसे दिखने वाले इस्तेमालों में से एक।
  • पुरानी crypt(3) पासवर्ड वर्णमाला सही तरह से सॉर्ट होती है: सॉर्ट की हुई एन्कोडेड स्ट्रिंग्स वही क्रम में खड़ी होती हैं जो सॉर्ट की हुई प्लेइंटएक्सट में होते हैं। GEDCOM 5.5 (1996) ने मल्टीमीडिया फील्ड्स के लिए वह वर्णमाला इस्तेमाल की, 5.5.1 रिवीज़न ने वह फीचर गिरा दिया, और क्रेट आज भी वह आपके लिए साथ देता है।
  • BinHex, पुराना Macintosh रैपर, अपनी वर्णमाला ऐसे बनाई थी कि 7, O, g और o जैसे दृश्य रूप से मिलती-जुलती अक्षरों को बाहर रखा जाए। इंसानी आँखों के लिए बनाया गया एन्कोडर, spellcheck से पहले की दुनिया में।
  • क्रेट की अपनी FAQ पैडिंग के सवाल में सीधी है: बिना शक exabytes स्टोरेज और ट्रांसफ़र बेकार = बाइट्स पर बर्बाद हुए होंगे। टोल बूथ 1987 से शुल्क ले रहा है।
  • Base64 एनक्रिप्शन नहीं है। अगर होती, तो आप इस लेख के किसी भी उदाहरण का आउटपुट पढ़ ही नहीं पाते। यह खिड़की वाली सीट है, तहखाना नहीं।

छोटा संस्करण

अपने इंजन को चुनिए उस सफ़र के हिसाब से जो डेटा करेगा: BASE64_STANDARD सब कुछ ऐसा, जिसे आप ख़ुद भी डिकोड करते हैं, _NO_PAD इंजन तब जब आप दोनों सिरे संभालते हैं और बाइट्स वापस चाहते हैं, URL_SAFE_NO_PAD टोकन और URLs के लिए, और कस्टम Alphabet बस तब जब प्रोटोकॉल ज़िद करे। बफ़रों को encoded_len() से साइज़ कीजिए, बड़ी चीज़ें EncoderWriter से स्ट्रीम कीजिए और हमेशा finish() के साथ बंद कीजिए, लाइन्स को line-wrap और pem से रैप कीजिए बस तब जब फ़ॉर्मैट माँगता हो, जहाँ तक हो सके SIMD इंजनों को भारी काम करने दीजिए, और याद रखिए कि चार-बदल-तीन सौदा सिर्फ़ टेक्स्ट वाले दरवाज़े से गुज़रने की कीमत है। सब कुछ एन्कोड कीजिए, और बस वही सुरक्षित रखिए जिसको असली लॉक चाहिए। और जब आपको उल्टी दिशा में जाने की ज़रूरत हो - स्ट्रिंग को वापस उसी बाइट्स में उतारना जिन्होंने सफ़र शुरू किया था - तो sister लेख Rust में डिकोडिंग कवर करता है, एक्ज़ैक्ट एरर मैसेज के पूरे स्कोरकार्ड के साथ।

अंतिम अपडेट: 2026-09-08

संबंधित लेख: Rust में Base64 डिकोडिंग: एक सम्पूर्ण गाइड