Javascript fileReader.readAsBinaryString 上传文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7431365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
fileReader.readAsBinaryString to upload files
提问by Smudge
Trying to use fileReader.readAsBinaryString to upload a PNG file to the server via AJAX, stripped down code (fileObject is the object containing info on my file);
尝试使用 fileReader.readAsBinaryString 通过 AJAX 将 PNG 文件上传到服务器,精简代码(fileObject 是包含我的文件信息的对象);
var fileReader = new FileReader();
fileReader.onload = function(e) {
var xmlHttpRequest = new XMLHttpRequest();
//Some AJAX-y stuff - callbacks, handlers etc.
xmlHttpRequest.open("POST", '/pushfile', true);
var dashes = '--';
var boundary = 'aperturephotoupload';
var crlf = "\r\n";
//Post with the correct MIME type (If the OS can identify one)
if ( fileObject.type == '' ){
filetype = 'application/octet-stream';
} else {
filetype = fileObject.type;
}
//Build a HTTP request to post the file
var data = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=\"file\";" + "filename=\"" + unescape(encodeURIComponent(fileObject.name)) + "\"" + crlf + "Content-Type: " + filetype + crlf + crlf + e.target.result + crlf + dashes + boundary + dashes;
xmlHttpRequest.setRequestHeader("Content-Type", "multipart/form-data;boundary=" + boundary);
//Send the binary data
xmlHttpRequest.send(data);
}
fileReader.readAsBinaryString(fileObject);
Examining the first few lines of a file before upload (using VI) gives me
在上传之前检查文件的前几行(使用 VI)给了我
The same file after upload shows
上传后显示同一个文件
So it looks like a formatting/encoding issue somewhere, I tried using a simple UTF8 encode function on the raw binary data
所以它看起来像是某个地方的格式/编码问题,我尝试在原始二进制数据上使用简单的 UTF8 编码函数
function utf8encode(string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
)
Then in the original code
然后在原代码中
//Build a HTTP request to post the file
var data = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=\"file\";" + "filename=\"" + unescape(encodeURIComponent(file.file.name)) + "\"" + crlf + "Content-Type: " + filetype + crlf + crlf + utf8encode(e.target.result) + crlf + dashes + boundary + dashes;
which gives me the output of
这给了我输出
Still not what the raw file was =(
仍然不是原始文件是什么 =(
How do I encode/load/process the file to avoid the encoding issues, so the file being received in the HTTP request is the same as the file before it was uploaded.
我如何编码/加载/处理文件以避免编码问题,因此 HTTP 请求中接收的文件与上传之前的文件相同。
Some other possibly useful information, if instead of using fileReader.readAsBinaryString() I use fileObject.getAsBinary() to get the binary data, it works fine. But getAsBinary only works in Firefox. I've been testing this in Firefox and Chrome, both on Mac, getting the same result in both. The backend uploads are being handled by the NGINX Upload Module, again running on Mac. The server and client are on the same machine. The same thing is happening with any file I try to upload, I just chose PNG because it was the most obvious example.
其他一些可能有用的信息,如果不是使用 fileReader.readAsBinaryString() 我使用 fileObject.getAsBinary() 来获取二进制数据,它工作正常。但是 getAsBinary 仅适用于 Firefox。我一直在 Mac 上的 Firefox 和 Chrome 中对此进行测试,两者都得到了相同的结果。后端上传由NGINX 上传模块处理,再次在 Mac 上运行。服务器和客户端在同一台机器上。我尝试上传的任何文件都会发生同样的事情,我只是选择了 PNG,因为它是最明显的例子。
采纳答案by c69
Use fileReader.readAsDataURL( fileObject )
, this will encode it to base64, which you can safely upload to your server.
使用fileReader.readAsDataURL( fileObject )
,这会将其编码为 base64,您可以安全地将其上传到您的服务器。
回答by KrisWebDev
(Following is a late but complete answer)
(以下是一个迟到但完整的答案)
FileReader methods support
FileReader 方法支持
FileReader.readAsBinaryString()
is deprecated. Don't use it!It's no longer in the W3C File API working draft:
FileReader.readAsBinaryString()
已弃用。不要使用它!它不再在W3C File API 工作草案中:
void abort();
void readAsArrayBuffer(Blob blob);
void readAsText(Blob blob, optional DOMString encoding);
void readAsDataURL(Blob blob);
NB: Note that File
is a kind of extended Blob
structure.
注意:注意这File
是一种扩展Blob
结构。
Mozilla still implements readAsBinaryString()
and describes it in MDN FileApi documentation:
Mozilla 仍然readAsBinaryString()
在MDN FileApi 文档中实现和描述它:
void abort();
void readAsArrayBuffer(in Blob blob); Requires Gecko 7.0
void readAsBinaryString(in Blob blob);
void readAsDataURL(in Blob file);
void readAsText(in Blob blob, [optional] in DOMString encoding);
The reason behind readAsBinaryString()
deprecation is in my opinion the following: the standard for JavaScript strings are DOMString
which only accept UTF-8 characters, NOT random binary data. So don't use readAsBinaryString(), that's not safe and ECMAScript-compliant at all.
readAsBinaryString()
我认为弃用的原因如下:JavaScript 字符串的标准是DOMString
只接受 UTF-8 字符,而不是随机二进制数据。所以不要使用 readAsBinaryString(),这根本不安全且不符合 ECMAScript 标准。
We know that JavaScript strings are not supposed to store binary databut Mozilla in some sort can. That's dangerous in my opinion. Blob
and typed arrays
(ArrayBuffer
and the not-yet-implemented but not necessary StringView
) were invented for one purpose: allow the use of pure binary data, without UTF-8 strings restrictions.
我们知道JavaScript 字符串不应该存储二进制数据,但 Mozilla 可以。在我看来这很危险。Blob
和typed arrays
(ArrayBuffer
以及尚未实现但不必要的StringView
)是为了一个目的而发明的:允许使用纯二进制数据,没有 UTF-8 字符串限制。
XMLHttpRequest upload support
XMLHttpRequest 上传支持
XMLHttpRequest.send()
has the following invocations options:
XMLHttpRequest.send()
具有以下调用选项:
void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
XMLHttpRequest.sendAsBinary()
has the following invocations options:
XMLHttpRequest.sendAsBinary()
具有以下调用选项:
void sendAsBinary( in DOMString body );
sendAsBinary() is NOT a standard and may not be supported in Chrome.
sendAsBinary() 不是标准,Chrome 可能不支持。
Solutions
解决方案
So you have several options:
所以你有几个选择:
send()
theFileReader.result
ofFileReader.readAsArrayBuffer ( fileObject )
. It is more complicated to manipulate (you'll have to make a separate send() for it) but it's the RECOMMENDED APPROACH.send()
theFileReader.result
ofFileReader.readAsDataURL( fileObject )
. It generates useless overhead and compression latency, requires a decompression step on the server-side BUT it's easy to manipulate as a string in Javascript.- Being non-standard and
sendAsBinary()
theFileReader.result
ofFileReader.readAsBinaryString( fileObject )
send()
对FileReader.result
的FileReader.readAsArrayBuffer ( fileObject )
。操作起来更复杂(你必须为它做一个单独的 send() ),但这是推荐的方法。send()
对FileReader.result
的FileReader.readAsDataURL( fileObject )
。它会产生无用的开销和压缩延迟,需要在服务器端进行解压缩步骤,但它很容易在 Javascript 中作为字符串进行操作。- 作为非标及
sendAsBinary()
对FileReader.result
的FileReader.readAsBinaryString( fileObject )
MDNstates that:
MDN指出:
The best way to send binary content (like in files upload) is using ArrayBuffers or Blobs in conjuncton with the send() method. However, if you want to send a stringifiable raw data, use the sendAsBinary() method instead, or the StringView (Non native) typed arrays superclass.
发送二进制内容(如文件上传)的最佳方式是将 ArrayBuffers 或 Blob 与 send() 方法结合使用。但是,如果要发送可字符串化的原始数据,请改用 sendAsBinary() 方法或 StringView(非本机)类型化数组超类。
回答by Ralf
The best way in browsers that support it, is to send the file as a Blob, or using FormData if you want a multipart form. You do not need a FileReader for that. This is both simpler and more efficient than trying to read the data.
在支持它的浏览器中,最好的方法是将文件作为 Blob 发送,或者如果您想要多部分表单,则使用 FormData。为此,您不需要 FileReader。这比尝试读取数据更简单、更有效。
If you specifically want to send it as multipart/form-data
, you can use a FormData object:
如果您特别想将其作为 发送multipart/form-data
,您可以使用 FormData 对象:
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", '/pushfile', true);
var formData = new FormData();
// This should automatically set the file name and type.
formData.append("file", file);
// Sending FormData automatically sets the Content-Type header to multipart/form-data
xmlHttpRequest.send(formData);
You can also send the data directly, instead of using multipart/form-data
. See the documentation. Of course, this will need a server-side change as well.
您也可以直接发送数据,而不是使用multipart/form-data
. 请参阅文档。当然,这也需要服务器端的更改。
// file is an instance of File, e.g. from a file input.
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", '/pushfile', true);
xmlHttpRequest.setRequestHeader("Content-Type", file.type);
// Send the binary data.
// Since a File is a Blob, we can send it directly.
xmlHttpRequest.send(file);
For browser support, see: http://caniuse.com/#feat=xhr2(most browsers, including IE 10+).
有关浏览器支持,请参阅:http: //caniuse.com/#feat=xhr2(大多数浏览器,包括 IE 10+)。