2013-03-01 55 views
8

我想從文件系統中讀取二進制文件,然後base64在JavaScript中進行編碼。我使用FileReader API來讀取數據,發現base64編碼器here閱讀和base64編碼的二進制文件

代碼我似乎接近工作,問題是生成的base64數據是錯誤的。下面是我到目前爲止有:

function saveResource() { 
    var file = $(".resourceFile")[0].files[0]; 

    var reader = new FileReader(); 
    reader.onload = function(evt) { 
     var fileData = evt.target.result; 
     var bytes = new Uint8Array(fileData); 
     var binaryText = ''; 

     for (var index = 0; index < bytes.byteLength; index++) { 
      binaryText += String.fromCharCode(bytes[index]); 
     } 

     console.log(Base64.encode(binaryText)); 

    }; 
    reader.readAsArrayBuffer(file); 
}; 

這裏是我與測試文件(這是一個100×100藍方):

enter image description here

根據一online base64 decoder/encoder,這個文件應該編碼於:

/9J/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIy MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4 + Tl5ufo6erx8vP09fb3 + PN6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3 + PN6/9oADAMBAAIRAxEAPwDxyiiiv3E8wKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA //ž

...而是什麼我得到了JavaScript的是:

W7/DmMO/w6AAEEpGSUYAAQIAAAEAAQAAw7/DmwBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDLDv8ObAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMsO/w4AAEQgAZABkAwEiAAIRAQMRAcO/w4QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoLw7/DhADCtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDLCgcKRwqEII0LCscOBFVLDkcOwJDNicsKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5esKDwoTChcKGwofCiMKJworCksKTwpTClcKWwpfCmMKZwprCosKjwqTCpcKmwqfCqMKpwqrCssKzwrTCtcK2wrfCuMK5wrrDgsODw4TDhcOGw4fDiMOJw4rDksOTw5TDlcOWw5fDmMOZw5rDocOiw6PDpMOlw6bDp8Oow6nDqsOxw7LDs8O0w7XD tsO3w7jDucO6w7/DhAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgvDv8OEAMK1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIywoEIFELCkcKhwrHDgQkjM1LDsBVicsORChYkNMOhJcOxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXrCgsKDwoTChcKGwofCiMKJworCksKTwpTClcKWwpfCmMKZwprCosKjwqTCpcKmwqfCqMKpwqrCssKzwrTCtcK2wrfCuMK5wrrDgsODw4TDhcOGw4fDiMOJw4rDksOTw5TDlcOWw5fDmMOZw5rDosOjw6TDpcOmw6fDqMOpw6rDssOzw7TDtcO2w7fDuMO5w7rDv8OaAAwDAQACEQMRAD8Aw7HDiijCosK/cTzDgMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooA8O/w5k =

如果我不得不冒險猜測,我會說這個問題與二進制數據中的不可打印字符有關(如果我編碼一個純文本文件,那很好)。但是,解決此問題的最佳方法是什麼?

編輯

它看起來像這可能是與以base64庫本身問題(或者,如果不是,則與Uint8Array是如何包裝的成庫調用的字符串)。如果我使用瀏覽器的btoa()函數,並直接通過它Uint8ArraybinaryText,那有效。太糟糕了,這個功能在所有瀏覽器中都不存在。

回答

8

和谷歌救援。我發現下面的代碼將輸入數據視爲一個普通的「字節」數組(數字在0到255之間,包括0;如果Uint8Array直接傳遞給它,也可以正常工作),並將其添加到我正在使用的庫中:

//note: it is assumed that the Base64 object has already been defined 
//License: Apache 2.0 
Base64.byteToCharMap_ = null; 
Base64.charToByteMap_ = null; 
Base64.byteToCharMapWebSafe_ = null; 
Base64.charToByteMapWebSafe_ = null; 
Base64.ENCODED_VALS_BASE = 
    'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 
    'abcdefghijklmnopqrstuvwxyz' + 
    ''; 

/** 
* Our default alphabet. Value 64 (=) is special; it means "nothing." 
* @type {string} 
*/ 
Base64.ENCODED_VALS = Base64.ENCODED_VALS_BASE + '+/='; 
Base64.ENCODED_VALS_WEBSAFE = Base64.ENCODED_VALS_BASE + '-_.'; 

/** 
* Base64-encode an array of bytes. 
* 
* @param {Array.<number>|Uint8Array} input An array of bytes (numbers with 
*  value in [0, 255]) to encode. 
* @param {boolean=} opt_webSafe Boolean indicating we should use the 
*  alternative alphabet. 
* @return {string} The base64 encoded string. 
*/ 
Base64.encodeByteArray = function(input, opt_webSafe) { 
    Base64.init_(); 

    var byteToCharMap = opt_webSafe ? 
         Base64.byteToCharMapWebSafe_ : 
         Base64.byteToCharMap_; 

    var output = []; 

    for (var i = 0; i < input.length; i += 3) { 
    var byte1 = input[i]; 
    var haveByte2 = i + 1 < input.length; 
    var byte2 = haveByte2 ? input[i + 1] : 0; 
    var haveByte3 = i + 2 < input.length; 
    var byte3 = haveByte3 ? input[i + 2] : 0; 

    var outByte1 = byte1 >> 2; 
    var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4); 
    var outByte3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6); 
    var outByte4 = byte3 & 0x3F; 

    if (!haveByte3) { 
     outByte4 = 64; 

     if (!haveByte2) { 
     outByte3 = 64; 
     } 
    } 

    output.push(byteToCharMap[outByte1], 
       byteToCharMap[outByte2], 
       byteToCharMap[outByte3], 
       byteToCharMap[outByte4]); 
    } 

    return output.join(''); 
}; 

/** 
* Lazy static initialization function. Called before 
* accessing any of the static map variables. 
* @private 
*/ 
Base64.init_ = function() { 
    if (!Base64.byteToCharMap_) { 
    Base64.byteToCharMap_ = {}; 
    Base64.charToByteMap_ = {}; 
    Base64.byteToCharMapWebSafe_ = {}; 
    Base64.charToByteMapWebSafe_ = {}; 

    // We want quick mappings back and forth, so we precompute two maps. 
    for (var i = 0; i < Base64.ENCODED_VALS.length; i++) { 
     Base64.byteToCharMap_[i] = 
      Base64.ENCODED_VALS.charAt(i); 
     Base64.charToByteMap_[Base64.byteToCharMap_[i]] = i; 
     Base64.byteToCharMapWebSafe_[i] = 
      Base64.ENCODED_VALS_WEBSAFE.charAt(i); 
     Base64.charToByteMapWebSafe_[ 
      Base64.byteToCharMapWebSafe_[i]] = i; 
    } 
    } 
}; 

用於容納上述功能庫中的全碼是available here,但在其未經修飾形式似乎取決於許多其他的庫。上面稍微破解的版本應該適用於任何需要快速修復此問題的人。

+0

這正是我期待的 - 發佈的解碼部分的任何機會呢? – Graham 2014-02-03 16:46:31

+1

我沒有自己的解碼部分版本,因爲我不需要它來解決我的問題(在我的情況下解碼是在服務器端完成的)。不過,Google的原始代碼可以在這裏找到:http://docs.closure-library.googlecode.com/git/closure_goog_crypt_base64.js.source.html – aroth 2014-02-04 05:04:39

+0

是的,看着那個,但它有你的依賴關係刪除在您的編碼片,所以我希望有類似的東西,但謝謝你的答覆。 – Graham 2014-02-04 11:14:08

2

將二進制視爲arraybuffer,這與任何字符編碼無關。你的藍色方塊(.jpg)有361個本地字節,意思是0..255(十進制)的八位字節,它們不是字符!

這意味着:使用ArrayBuffer將其編碼爲具有衆所周知的base64算法的Base64。

用Perl回到原點,表示藍色方形如上:

my $fh = IO::File->new; 
$fh->open("d:/tmp/x.jpg", O_BINARY|O_CREAT|O_RDWR|O_TRUNC) or die $!; 

$fh->print(decode_base64("/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBD 
AQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAFQABAQAA 
AAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAUH/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMR 
AD8AjgDcUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//2Q== 
")); 


$fh->close;