Chuyển đổi chuỗi base64 thành ArrayBuffer


98

Tôi cần chuyển đổi chuỗi mã hóa base64 thành Bộ đệm ArrayBuffer. Các chuỗi base64 là đầu vào của người dùng, chúng sẽ được sao chép và dán từ email, vì vậy chúng không ở đó khi trang được tải. Tôi muốn thực hiện việc này bằng javascript mà không cần thực hiện lệnh gọi ajax tới máy chủ nếu có thể.

Tôi thấy những liên kết đó thú vị, nhưng chúng không giúp được tôi:

ArrayBuffer đến chuỗi mã hóa base64

đây là về chuyển đổi ngược lại, từ ArrayBuffer sang base64, không phải ngược lại

http://jsperf.com/json-vs-base64/2

điều này có vẻ tốt nhưng tôi không thể tìm ra cách sử dụng mã.

Có cách nào dễ dàng (có thể là bản địa) để thực hiện chuyển đổi không? cảm ơn

Câu trả lời:


147

Thử cái này:

function _base64ToArrayBuffer(base64) {
    var binary_string = window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array(len);
    for (var i = 0; i < len; i++) {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}

3
Xin hãy giải thích cho tôi những gì đang thực sự xảy ra ở đây.
Govi S

4
Nó khá đơn giản, đầu tiên chúng ta giải mã chuỗi base64 (atob), sau đó chúng ta tạo một mảng mới gồm các số nguyên không dấu 8-bit có cùng độ dài với chuỗi đã giải mã. Sau đó, chúng tôi lặp lại chuỗi và điền vào mảng với giá trị Unicode của mỗi ký tự trong chuỗi.
Goran.it

2
Từ MDN: Base64 là một nhóm các lược đồ mã hóa nhị phân thành văn bản tương tự biểu thị dữ liệu nhị phân ở định dạng chuỗi ASCII bằng cách dịch nó thành biểu diễn cơ số 64. Các Uint8Array gõ mảng đại diện cho một mảng các số nguyên unsigned 8-bit, và chúng tôi đang làm việc với đại diện ASCII của dữ liệu (mà cũng là một bảng 8-bit) ..
Goran.it

3
Điều này LAF không đúng. Nó cho phép javascript giải thích các byte dưới dạng chuỗi, ảnh hưởng đến dữ liệu thực sự là nhị phân thực.
Tomáš Zato - Phục hồi Monica

4
vấn đề là a) không phải mọi dãy byte có giá trị unicode b) không phải mọi nhân vật trong unicode là một byte, vì thế bytes[i] = binary_string.charCodeAt(i);có thể là sai lầm
hỗn hợp

52

Sử dụng TypedArray.from :

Uint8Array.from(atob(base64_string), c => c.charCodeAt(0))

Hiệu suất được so sánh với phiên bản vòng lặp for của câu trả lời Goran.it.


2
Đối với những người thích loại lót này, hãy nhớ rằng Uint8Array.fromvẫn có ít khả năng tương thích với một số trình duyệt.
IzumiSy 17/02/17

2
Vui lòng không đề xuất atob hoặc btoa: developer.mozilla.org/en-US/docs/Web/API/WindowBase64/…
Kugel

trình biên dịch rails không thể xử lý chuỗi này và không thành công với ExecJS::RuntimeError: SyntaxError: Unexpected token: operator (>); (đường ray 5)
Avael Kross

3
Đây không phải là bộ đệm mảng. Đây là mảng đã nhập. Bạn nhận được quyền truy cập vào bộ đệm mảng thông qua các .buffertài sản của những gì được trả về từUint8Array
oligofren

4
@Saites, Không có gì sai với atobhoặc btoa, bạn chỉ cần cung cấp cho họ thông tin đầu vào hợp lệ. atobcần một chuỗi base64 hợp lệ, nếu không, nó sẽ báo lỗi. Và btoacần một chuỗi byte hợp lệ (còn gọi là chuỗi nhị phân) là chuỗi chứa các ký tự trong phạm vi 0-255. Nếu chuỗi của bạn có các ký tự nằm ngoài phạm vi đó, btoasẽ gây ra lỗi.
GetFree

34

Câu trả lời của Goran.it không hoạt động do sự cố unicode trong javascript - https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding .

Tôi đã kết thúc bằng cách sử dụng hàm được cung cấp trên blog của Daniel Guerrero: http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/

Hàm được liệt kê trên liên kết github: https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

Sử dụng những dòng này

var uintArray = Base64Binary.decode(base64_string);  
var byteArray = Base64Binary.decodeArrayBuffer(base64_string); 

1
Phương pháp này nhanh hơn gấp 2 lần so với sử dụng atob.
xiaoyu2er

4
Bạn có thể đưa ra một ví dụ mà nó sẽ không hoạt động? Bài báo nói về mã hóa các chuỗi tùy ý, có thể chứa các ký tự unicode, nhưng hoàn toàn không áp dụng cho atob.
riv

1
decodeArrayBuffertrả về một ArrayBufferkích thước luôn chia hết cho 3, tôi không hiểu đó là do thiết kế hay do lỗi. Tôi sẽ hỏi trong dự án github.
ceztko 19/09/18

@ceztko Có thể là do (tình cờ) thiết kế. Thuật toán mã hóa base64 lấy các nhóm 3 byte và biến chúng thành 4 ký tự. Phương thức giải mã có thể phân bổ một Bộ đệm ArrayBuffer có độ dài là base64String.length / 4 * 3 byte và không bao giờ cắt bớt bất kỳ byte nào không sử dụng khi hoàn tất.
AlwaysLearning

1
@AlwaysLearning có nghĩa là nó có thể bị nghe trộm vì các byte 0 còn lại có thể làm hỏng nội dung đầu ra dự kiến.
ceztko

21

Vừa tìm thấy base64-arraybuffer, một gói npm nhỏ với mức sử dụng cực kỳ cao, 5 triệu lượt tải xuống vào tháng trước (2017-08).

https://www.npmjs.com/package/base64-arraybuffer

Đối với bất kỳ ai đang tìm kiếm một giải pháp tiêu chuẩn tốt nhất, đây có thể là nó.


9

Async giải pháp, nó tốt hơn khi dữ liệu lớn:

// base64 to buffer
function base64ToBufferAsync(base64) {
  var dataUrl = "data:application/octet-binary;base64," + base64;

  fetch(dataUrl)
    .then(res => res.arrayBuffer())
    .then(buffer => {
      console.log("base64 to buffer: " + new Uint8Array(buffer));
    })
}

// buffer to base64
function bufferToBase64Async( buffer ) {
    var blob = new Blob([buffer], {type:'application/octet-binary'});    
    console.log("buffer to blob:" + blob)

    var fileReader = new FileReader();
    fileReader.onload = function() {
      var dataUrl = fileReader.result;
      console.log("blob to dataUrl: " + dataUrl);

      var base64 = dataUrl.substr(dataUrl.indexOf(',')+1)      
      console.log("dataUrl to base64: " + base64);
    };
    fileReader.readAsDataURL(blob);
}

6

Javascript là một môi trường phát triển tốt nên có vẻ kỳ lạ hơn là nó không cung cấp giải pháp cho vấn đề nhỏ này. Các giải pháp được cung cấp ở những nơi khác trên trang này có thể chậm. Đây là giải pháp của tôi. Nó sử dụng chức năng có sẵn để giải mã url dữ liệu âm thanh và hình ảnh base64.

var req = new XMLHttpRequest;
req.open('GET', "data:application/octet;base64," + base64Data);
req.responseType = 'arraybuffer';
req.onload = function fileLoaded(e)
{
   var byteArray = new Int8Array(e.target.response);
   // var shortArray = new Int16Array(e.target.response);
   // var unsignedShortArray = new Int16Array(e.target.response);
   // etc.
}
req.send();

Yêu cầu gửi không thành công nếu chuỗi 65 cơ sở được tạo sai.

Loại kịch câm (ứng dụng / octet) có lẽ là không cần thiết.

Đã thử nghiệm trong chrome. Sẽ hoạt động trong các trình duyệt khác.


1
Đây là giải pháp hoàn hảo cho tôi, đơn giản và sạch sẽ. Tôi đã nhanh chóng thử nghiệm nó trên Firefox, IE 11, Edge và hoạt động tốt!
cs-NET

không liên quan đến câu hỏi ban đầu
James Newton

Tôi không chắc nó hoạt động như thế nào đối với bạn trong IE11, nhưng tôi gặp Access Deniedlỗi, có vẻ là một hạn chế của CORS.
Sergiu

6

Đối với người dùng Node.js:

const myBuffer = Buffer.from(someBase64String, 'base64');

myBuffer sẽ thuộc loại Buffer là một lớp con của Uint8Array. Thật không may, Uint8Array KHÔNG phải là bộ đệm ArrayBuffer như OP đã yêu cầu. Nhưng khi thao tác ArrayBuffer, tôi hầu như luôn bọc nó bằng Uint8Array hoặc thứ gì đó tương tự, vì vậy nó phải gần với những gì được yêu cầu.


2

JS thuần túy - không có chuỗi middlestep (không có atob)

Tôi viết hàm sau đây chuyển đổi base64 theo cách trực tiếp (không chuyển đổi thành chuỗi ở middlestep). Ý TƯỞNG

  • nhận được 4 đoạn base64 ký tự
  • tìm chỉ mục của mỗi ký tự trong bảng chữ cái base64
  • chuyển đổi chỉ mục thành số 6 bit (chuỗi nhị phân)
  • nối bốn số 6 bit tạo ra số 24 bit (được lưu trữ dưới dạng chuỗi nhị phân)
  • chia chuỗi 24 bit thành ba chuỗi 8 bit và giấu từng chuỗi thành số và lưu trữ chúng trong mảng đầu ra
  • chữ hoa góc: nếu chuỗi base64 đầu vào kết thúc bằng một / hai ký tự =, hãy xóa một / hai số khỏi mảng đầu ra

Giải pháp dưới đây cho phép xử lý chuỗi base64 đầu vào lớn. Chức năng tương tự để chuyển đổi byte sang base64 mà không có btoa là TẠI ĐÂY


vậy không thiếu "."?
Gillsoft AB

Kiểm tra trong trình duyệt, tôi không chắc đây là kết quả mong đợi? "Alice's Adventure in Wonderland" (tức là nhân vật cuối cùng là NaN)
Gillsoft AB

1
@GillsoftAB cảm ơn bạn vì thông tin này - bạn nói đúng - tôi đã khắc phục sự cố
Kamil Kiełczewski

-3
const str = "dGhpcyBpcyBiYXNlNjQgc3RyaW5n"
const encoded = new TextEncoder().encode(str) // is Uint8Array
const buf = encoded.buffer // is ArrayBuffer

6
Lưu ý rằng điều này không thực hiện bất kỳ giải mã / mã hóa Base64 nào. Nó chỉ biến 6 byte của "base64" thành ArrayBuffer 6 phần tử hoặc Uint8Array.
dubek

2
@dubek đó là những gì đã được hỏi.
Andrii Nemchenko
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.