使用Javascript检索二进制文件内容,base64对其进行编码并使用Python进行反向解码

我试图使用XMLHttpRequest (使用最近的Webkit)下载一个二进制文件,并使用这个简单的函数对它的内容进行base64编码:

 function getBinary(file){ var xhr = new XMLHttpRequest(); xhr.open("GET", file, false); xhr.overrideMimeType("text/plain; charset=x-user-defined"); xhr.send(null); return xhr.responseText; } function base64encode(binary) { return btoa(unescape(encodeURIComponent(binary))); } var binary = getBinary('http://some.tld/sample.pdf'); var base64encoded = base64encode(binary); 

作为一个侧面说明,以上所有内容都是标准的Javascript东西,包括btoa()encodeURIComponent() : https : //developer.mozilla.org/en/DOM/window.btoa

这工作相当顺利,我甚至可以使用Javascript解码base64内容:

 function base64decode(base64) { return decodeURIComponent(escape(atob(base64))); } var decodedBinary = base64decode(base64encoded); decodedBinary === binary // true 

现在,我想使用Python解码base64编码的内容,它使用一些JSONstring来获得base64编码的string值。 天真地这就是我所做的:

 import urllib import base64 # ... retrieving of base64 encoded string through JSON base64 = "77+9UE5HDQ……………oaCgA=" source_contents = urllib.unquote(base64.b64decode(base64)) destination_file = open(destination, 'wb') destination_file.write(source_contents) destination_file.close() 

但是由此产生的文件是无效的,看起来像操作的UTF-8,编码或者我还不清楚的东西。

如果我在将UTF-8内容放入目标文件之前尝试解码,则会出现错误:

 import urllib import base64 # ... retrieving of base64 encoded string through JSON base64 = "77+9UE5HDQ……………oaCgA=" source_contents = urllib.unquote(base64.b64decode(base64)).decode('utf-8') destination_file = open(destination, 'wb') destination_file.write(source_contents) destination_file.close() $ python test.py // ... UnicodeEncodeError: 'ascii' codec can't encode character u'\ufffd' in position 0: ordinal not in range(128) 

作为一个侧面说明,这里是一个同一个文件的两个文本表示的截图。 左边:原文; 在右边:从base64解码的string创build的: http : //cl.ly/0U3G34110z3c132O2e2x

有没有一个已知的技巧来解决这些编码时尝试重新创build文件的问题? 你将如何实现这一点?

任何帮助或提示非常感谢:)

所以我正在回答自己 – 对此感到遗憾 – 但我认为这对于像我一样迷路的人可能是有用的;)

所以你必须使用ArrayBuffer ,并将XMLHttpRequest对象实例的responseType属性设置为arraybuffer以便检索Bytes的本地数组,可以使用以下方便的函数将其转换为base64(在这里find,作者可能会被祝福):

 function base64ArrayBuffer(arrayBuffer) { var base64 = '' var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' var bytes = new Uint8Array(arrayBuffer) var byteLength = bytes.byteLength var byteRemainder = byteLength % 3 var mainLength = byteLength - byteRemainder var a, b, c, d var chunk // Main loop deals with bytes in chunks of 3 for (var i = 0; i < mainLength; i = i + 3) { // Combine the three bytes into a single integer chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2] // Use bitmasks to extract 6-bit segments from the triplet a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18 b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12 c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6 d = chunk & 63 // 63 = 2^6 - 1 // Convert the raw binary segments to the appropriate ASCII encoding base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d] } // Deal with the remaining bytes and padding if (byteRemainder == 1) { chunk = bytes[mainLength] a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2 // Set the 4 least significant bits to zero b = (chunk & 3) << 4 // 3 = 2^2 - 1 base64 += encodings[a] + encodings[b] + '==' } else if (byteRemainder == 2) { chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1] a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10 b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4 // Set the 2 least significant bits to zero c = (chunk & 15) << 2 // 15 = 2^4 - 1 base64 += encodings[a] + encodings[b] + encodings[c] + '=' } return base64 } 

所以这是一个工作代码:

 var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://some.tld/favicon.png', false); xhr.responseType = 'arraybuffer'; xhr.onload = function(e) { console.log(base64ArrayBuffer(e.currentTarget.response)); }; xhr.send(); 

这将logging代表二进制文件内容的有效的 base64编码的string。

编辑:对于无法访问ArrayBuffer并且btoa()在编码字符上失败的旧浏览器,下面是获取任何二进制文件的base64编码版本的另一种方法:

 function getBinary(file){ var xhr = new XMLHttpRequest(); xhr.open("GET", file, false); xhr.overrideMimeType("text/plain; charset=x-user-defined"); xhr.send(null); return xhr.responseText; } function base64Encode(str) { var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var out = "", i = 0, len = str.length, c1, c2, c3; while (i < len) { c1 = str.charCodeAt(i++) & 0xff; if (i == len) { out += CHARS.charAt(c1 >> 2); out += CHARS.charAt((c1 & 0x3) << 4); out += "=="; break; } c2 = str.charCodeAt(i++); if (i == len) { out += CHARS.charAt(c1 >> 2); out += CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)); out += CHARS.charAt((c2 & 0xF) << 2); out += "="; break; } c3 = str.charCodeAt(i++); out += CHARS.charAt(c1 >> 2); out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); out += CHARS.charAt(c3 & 0x3F); } return out; } console.log(base64Encode(getBinary('http://www.google.frhttp://img.dovov.comsrpr/logo3w.png'))); 

希望这有助于其他人,因为它为我做了。