U648 ऐरे को बेस 64 एनकोडेड स्ट्रिंग में कैसे बदलें?


90

मुझे एक वेब सॉकेट कॉम्यूनिकेशन मिला है, मैं बेस 64 एनकोडेड स्ट्रिंग प्राप्त करता हूं, इसे uint8 में कन्वर्ट करता हूं और इस पर काम करता हूं, लेकिन अब मुझे वापस भेजने की जरूरत है, मुझे uint8 एरे मिल गया है, और इसे बेस 64 स्ट्रिंग में बदलने की जरूरत है, इसलिए मैं इसे भेज सकता हूं। मैं यह रूपांतरण कैसे कर सकता हूं?



प्रश्न "ArrayBuffer to base64 एन्कोडेड स्ट्रिंग" में एक बेहतर समाधान होता है जो सभी वर्णों को संभालता है। stackoverflow.com/questions/9267899/…
स्टीव हनोव

जवाबों:


16

पहले से ही प्रस्तावित सभी समाधानों में गंभीर समस्याएं हैं। कुछ समाधान बड़े सरणियों पर काम करने में विफल होते हैं, कुछ गलत आउटपुट प्रदान करते हैं, कुछ ने बोटो कॉल पर एक त्रुटि फेंक दी अगर एक मध्यवर्ती स्ट्रिंग में मल्टीबीट वर्ण होते हैं, तो कुछ आवश्यकता से अधिक मेमोरी का उपभोग करते हैं।

इसलिए मैंने एक सीधा रूपांतरण फ़ंक्शन लागू किया, जो इनपुट की परवाह किए बिना काम करता है। यह मेरी मशीन पर प्रति सेकंड लगभग 5 मिलियन बाइट्स को परिवर्तित करता है।

https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727


क्या यह एक स्ट्रिंग बनाने की तुलना में तार के एक सरणी के रूप में base64abc है? "ABCDEFG..."?
गेर गॉडफ्रे 19

163

यदि आपके डेटा में मल्टी-बाइट अनुक्रम (सादा ASCII अनुक्रम नहीं) हो सकता है और आपके ब्राउज़र में TextDecoder है , तो आपको अपने डेटा को डीकोड करने के लिए इसका उपयोग करना चाहिए (TextDecoder के लिए आवश्यक एन्कोडिंग निर्दिष्ट करें):

var u8 = new Uint8Array([65, 66, 67, 68]);
var decoder = new TextDecoder('utf8');
var b64encoded = btoa(decoder.decode(u8));

यदि आपको उन ब्राउज़रों का समर्थन करने की आवश्यकता है, जिनके पास टेक्सडकोडर (वर्तमान में केवल IE और एज) नहीं है, तो सबसे अच्छा विकल्प एक टेक्स्टडेकोडर पॉलीफिल का उपयोग करना है ।

यदि आपके डेटा में सादा ASCII (मल्टीबाइट यूनिकोड / यूटीएफ -8 नहीं है) है, तो एक सरल विकल्प है String.fromCharCodeजिसका उपयोग करते हुए उसे सार्वभौमिक रूप से समर्थित होना चाहिए:

var ascii = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(String.fromCharCode.apply(null, ascii));

और बेस 64 स्ट्रिंग को यूइंट 8 ओर में वापस डिकोड करना है।

var u8_2 = new Uint8Array(atob(b64encoded).split("").map(function(c) {
    return c.charCodeAt(0); }));

यदि आपके पास बहुत बड़े सरणी बफ़र हैं, तो आवेदन विफल हो सकता है और आपको बफर (@RohitSengar द्वारा पोस्ट किए गए के आधार पर) को चंक करने की आवश्यकता हो सकती है। फिर से, ध्यान दें कि यह केवल तभी सही है जब आपके बफर में केवल गैर-मल्टीबैटी ASCII वर्ण हों:

function Uint8ToString(u8a){
  var CHUNK_SZ = 0x8000;
  var c = [];
  for (var i=0; i < u8a.length; i+=CHUNK_SZ) {
    c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ)));
  }
  return c.join("");
}
// Usage
var u8 = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(Uint8ToString(u8));

4
यह फ़ायरफ़ॉक्स में मेरे लिए काम कर रहा है, लेकिन क्रोम "अनकॉन्डेड रेंजऑयर: अधिकतम कॉल स्टैक आकार को पार कर गया" (बोटा कर) के साथ चुटकुले।
माइकल पॉलुकोनिस

3
@MichaelPaulukonis मेरा अनुमान है कि यह वास्तव में String.fromCharCode.apply है जो स्टैक आकार को पार करने का कारण बन रहा है। यदि आपके पास एक बहुत बड़ा Uint8Array है, तो आपको संभवतः ऐसा करने के लिए एप्लिकेशन का उपयोग करने के बजाय स्ट्रिंग को पुन: बनाने की आवश्यकता होगी। आवेदन () कॉल आपके सरणी के प्रत्येक तत्व को एक पैरामीटर के रूप में fromCharCode से गुजर रहा है, इसलिए यदि सरणी 128000 बाइट्स लंबा है तो आप 128000 मापदंडों के साथ एक फ़ंक्शन कॉल करने की कोशिश कर रहे होंगे जो स्टैक को उड़ाने की संभावना है।
कनक

4
धन्यवाद। मेरी जरूरत थीbtoa(String.fromCharCode.apply(null, myArray))
ग्लेन लिटिल

29
यह काम नहीं करता है यदि बाइट सरणी मान्य यूनिकोड नहीं है।
मेलब

11
बेस 64 स्ट्रिंग में, या में कोई मल्टीबाइट कैरेक्टर नहीं हैं Uint8ArrayTextDecoderयहाँ उपयोग करने के लिए बिल्कुल गलत बात है, क्योंकि यदि आपकी Uint8Arrayसीमा 128..255 में है, तो टेक्स्ट डिकोडर गलती से उन्हें यूनिकोड वर्णों में बदल देगा, जो बेस 64 कनवर्टर को तोड़ देगा।
riv

26

जावास्क्रिप्ट के लिए बहुत सरल समाधान और परीक्षण!

ToBase64 = function (u8) {
    return btoa(String.fromCharCode.apply(null, u8));
}

FromBase64 = function (str) {
    return atob(str).split('').map(function (c) { return c.charCodeAt(0); });
}

var u8 = new Uint8Array(256);
for (var i = 0; i < 256; i++)
    u8[i] = i;

var b64 = ToBase64(u8);
console.debug(b64);
console.debug(FromBase64(b64));

4
सबसे साफ समाधान!
realappie

सही समाधान
हरिस उर रहमान

2
यह बड़े डेटा (जैसे छवियों) पर विफल रहता हैRangeError: Maximum call stack size exceeded
मैक्सिम खोखरीकोव

21

यदि आप Node.js का उपयोग कर रहे हैं तो आप Uint8Array को बेस 64 में बदलने के लिए इस कोड का उपयोग कर सकते हैं

var b64 = Buffer.from(u8).toString('base64');

4
यह एक बेहतर जवाब है तो हाथ प्रदर्शन के मामले में ऊपर लुढ़का हुआ है।
बेन लियायनज

2
बहुत बढ़िया! धन्यवाद। सबसे अच्छा जवाब कभी
एलन

18
function Uint8ToBase64(u8Arr){
  var CHUNK_SIZE = 0x8000; //arbitrary number
  var index = 0;
  var length = u8Arr.length;
  var result = '';
  var slice;
  while (index < length) {
    slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length)); 
    result += String.fromCharCode.apply(null, slice);
    index += CHUNK_SIZE;
  }
  return btoa(result);
}

यदि आप एक बहुत बड़े Uint8Array है तो आप इस फ़ंक्शन का उपयोग कर सकते हैं। यह जावास्क्रिप्ट के लिए है, FileReader readAsArrayBuffer के मामले में उपयोगी हो सकता है।


2
दिलचस्प बात यह है कि क्रोम में मैंने इसे 300kb + बफर पर टाइम किया और पाया कि आप इसे बाइट के बजाए बाइट करने की तुलना में थोड़ा धीमा कर रहे हैं। इसने मुझे चौंका दिया।
मैट

@Matt दिलचस्प। यह संभव है कि इस बीच, क्रोम ने अब इस रूपांतरण का पता लगाया है और इसके लिए एक विशिष्ट अनुकूलन है और डेटा को कम करने से इसकी दक्षता कम हो सकती है।
kanaka

2
यह सुरक्षित नहीं है, क्या यह है? यदि मेरी बंक की सीमा मल्टी-बाइट UTF8 एनकोडेड कैरेक्टर से कटती है , तो CCCCode () बाउंड्री के दोनों तरफ बाइट्स से समझदार कैरेक्टर नहीं बना पाएगी, क्या ऐसा होगा?
जेन्स

2
@Jens String.fromCharCode.apply()विधियाँ UTF-8 को पुन: उत्पन्न नहीं कर सकती हैं: UTF-8 वर्ण एक बाइट से चार बाइट्स की लंबाई में भिन्न हो सकते हैं, फिर भी String.fromCharCode.apply()UInt8 के सेगमेंट में UInt8Array की जांच करते हैं, इसलिए यह गलत तरीके से प्रत्येक चरित्र को एक बाइट लंबे और पड़ोसी से स्वतंत्र होने के लिए मानता है लोगों को। यदि इनपुट UInt8Array में इनकोड किए गए अक्षर ASCII (सिंगल-बाइट) रेंज में होते हैं, तो यह संयोग से काम करेगा, लेकिन यह पूर्ण UTF-8 को पुन: उत्पन्न नहीं कर सकता है। इसके लिए आपको TextDecoder या एक समान एल्गोरिथ्म की आवश्यकता है।
जेमी बिर्च

1
@Jens क्या बहु-बाइट UTF8 एक बाइनरी डेटा ऐरे में वर्णों को इनकोड करता है? हम यहां यूनिकोड स्ट्रिंग्स के साथ काम नहीं कर रहे हैं, लेकिन मनमाने ढंग से बाइनरी डेटा के साथ, जिसे utf-8 कोडपॉइंट के रूप में नहीं माना जाना चाहिए।
riv

0

यहाँ एक JS फ़ंक्शन है:

इस फ़ंक्शन की आवश्यकता है क्योंकि Chrome एक बेस 64 एनकोडेड स्ट्रिंग को मान के रूप में ApplicationServerKey के लिए pushManager.subscribe में नहीं लेता है फिर भी https://bugs.chromium.org/p/chromium/issues/detail?id/802280

function urlBase64ToUint8Array(base64String) {
  var padding = '='.repeat((4 - base64String.length % 4) % 4);
  var base64 = (base64String + padding)
    .replace(/\-/g, '+')
    .replace(/_/g, '/');

  var rawData = window.atob(base64);
  var outputArray = new Uint8Array(rawData.length);

  for (var i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

3
यह बेस 64 को यूंट 8 एरे में परिवर्तित करता है। लेकिन सवाल पूछता है कि Uint8Array को बेस 64 में कैसे बदला जाए
बैरी माइकल डॉयल

0

शुद्ध जेएस - कोई स्ट्रिंग मिडलस्टेप (कोई बोटो नहीं)

नीचे दिए गए समाधान में मैं स्ट्रिंग में रूपांतरण को छोड़ देता हूं। IDEA निम्नलिखित है:

  • 3 बाइट्स (3 एरे तत्व) से जुड़ें और आपको 24-बिट्स मिलते हैं
  • 24बिट्स को चार 6-बिट संख्या में विभाजित करें (जो 0 से 63 तक मान लेते हैं)
  • बेस 64 वर्णमाला में सूचकांक के रूप में उस संख्या का उपयोग करें
  • कोने का मामला: जब इनपुट बाइट सरणी में लंबाई 3 से विभाजित नहीं होती है तो परिणाम जोड़ें =या==

नीचे दिए गए समाधान 3-बाइट्स चंक्स पर काम करते हैं इसलिए यह बड़े सरणियों के लिए अच्छा है। बेस 64 को बाइनरी ऐरे (बिना atob) के कन्वर्ट करने का समान उपाय यहाँ है


मैं कॉम्पैक्टनेस पसंद करता हूं, लेकिन बाइनरी नंबर का प्रतिनिधित्व करने वाले तार में परिवर्तित करना और फिर स्वीकृत समाधान की तुलना में बहुत धीमा है।
गेर गॉडफ्रे 19

0

बेस 64 एनकोडेड स्ट्रिंग में uint8 एरे को कन्वर्ट करने के लिए निम्नलिखित का उपयोग करें

function arrayBufferToBase64(buffer) {
            var binary = '';
            var bytes = [].slice.call(new Uint8Array(buffer));
            bytes.forEach((b) => binary += String.fromCharCode(b));
            return window.btoa(binary);
        };


-3

यदि आप चाहते हैं कि एक बेस 64-एनकोडर का जेएस कार्यान्वयन है, ताकि आप डेटा वापस भेज सकें, तो आप btoaफ़ंक्शन को आज़मा सकते हैं ।

b64enc = btoa(uint);

Btoa पर त्वरित नोटों की एक जोड़ी - यह गैर-मानक है, इसलिए ब्राउज़रों को इसका समर्थन करने के लिए मजबूर नहीं किया जाता है। हालाँकि, अधिकांश ब्राउज़र करते हैं। बड़े वाले, कम से कम।atobविपरीत रूपांतरण है।

यदि आपको एक अलग कार्यान्वयन की आवश्यकता है, या आप एक किनारे-केस ढूंढते हैं, जहां ब्राउज़र को पता नहीं है कि आप किस बारे में बात कर रहे हैं, तो JS के लिए एक आधार 64 एनकोडर की खोज करना बहुत कठिन नहीं होगा।

मुझे लगता है कि उनमें से 3 मेरी कंपनी की वेबसाइट पर घूम रहे हैं, किसी कारण से ...


धन्यवाद, मैं पहले कि बाहर की कोशिश नहीं की।
काइयो केटो

10
नोटों की जोड़ी। btoa और atob वास्तव में HTML5 मानकीकरण प्रक्रिया का हिस्सा हैं और अधिकांश ब्राउज़र उन्हें पहले से ही उसी तरह से समर्थन करते हैं। दूसरे, बोटोआ और एटब केवल स्ट्रिंग्स के साथ काम करते हैं। Uint8Array पर रनिंग btoa पहले स्टर्लिंग () का उपयोग करके बफर को एक स्ट्रिंग में बदल देगा। इसके परिणामस्वरूप स्ट्रिंग "[ऑब्जेक्ट Uint8Array]" है। कि शायद इरादा नहीं है।
कनक

1
@CaioKeto आप अपने चयनित उत्तर को बदलने पर विचार कर सकते हैं। यह उत्तर सही नहीं है।
कनक

-4

npm गूगल-क्लोजर-लाइब्रेरी --save स्थापित करें

require("google-closure-library");
goog.require('goog.crypt.base64');

var result =goog.crypt.base64.encodeByteArray(Uint8Array.of(1,83,27,99,102,66));
console.log(result);

$node index.jsAVMbY2Y = कंसोल पर लिखना होगा ।


1
यह हास्यास्पद है कि -veमतदान का उत्तर एक अत्यधिक के बजाय स्वीकार किया जाता है +ve
विष्णुदेव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.