Javascript 用于上载文件的fileReader.readAsBinaryString

Javascript 用于上载文件的fileReader.readAsBinaryString,javascript,encoding,upload,filereader,Javascript,Encoding,Upload,Filereader,尝试使用fileReader.readAsBinaryString通过AJAX将PNG文件上载到服务器,简化代码(fileObject是包含我文件信息的对象) 在上传(使用VI)之前检查文件的前几行可以让我 上传后显示相同的文件 所以它看起来像是某个地方的格式化/编码问题,我尝试对原始二进制数据使用一个简单的UTF8编码函数 function utf8encode(string) { string = string.replace(/\r\n/g,"\n");

尝试使用fileReader.readAsBinaryString通过AJAX将PNG文件上载到服务器,简化代码(fileObject是包含我文件信息的对象)

在上传(使用VI)之前检查文件的前几行可以让我

上传后显示相同的文件

所以它看起来像是某个地方的格式化/编码问题,我尝试对原始二进制数据使用一个简单的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;
    )
这给了我

仍然不是原始文件的样子=(

如何对文件进行编码/加载/处理以避免编码问题,从而使HTTP请求中接收的文件与上载前的文件相同


如果不使用fileReader.readAsBinaryString()而使用fileObject.getAsBinary()的话,还有一些其他可能有用的信息为了获得二进制数据,它工作得很好。但是getAsBinary只在Firefox中工作。我已经在Firefox和Chrome中进行了测试,都在Mac上,得到了相同的结果。后端上传由处理,同样在Mac上运行。服务器和客户端在同一台机器上。我尝试上传的任何文件都会发生同样的事情,I just选择PNG是因为它是最明显的例子。

使用
文件阅读器。readAsDataURL(fileObject)
,这将把它编码到base64,你可以安全地上传到你的服务器。

(下面是一个很晚但完整的答案)

文件读取器方法支持
FileReader.readAsBinaryString()
已弃用。不要使用它!它不再位于:

注意:
File
是一种扩展的
Blob
结构

Mozilla仍然实现了
readAsBinaryString()
,并在以下内容中进行了描述:

我认为,
readAsBinaryString()
弃用的原因如下:JavaScript字符串的标准是
DOMString
,它只接受UTF-8字符,而不接受随机二进制数据。因此不要使用readAsBinaryString(),这既不安全,也不符合ECMAScript

我们知道JavaScript字符串不应该存储二进制数据,但Mozilla在某种程度上可以。在我看来,这是危险的。
Blob
类型化数组
ArrayBuffer
和尚未实现但不必要的
StringView
)它们的发明有一个目的:允许使用纯二进制数据,而不受UTF-8字符串的限制

XMLHttpRequest上传支持
具有以下调用选项:

void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
void sendAsBinary(   in DOMString body );
具有以下调用选项:

void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
void sendAsBinary(   in DOMString body );
sendAsBinary()不是标准,Chrome可能不支持它

解决
所以你有几个选择:

  • send()
    文件阅读器的
    FileReader.readAsArrayBuffer(fileObject)
    FileReader.result
    。操作起来更复杂(您必须为其单独发送()),但这是推荐的方法
  • send()
    FileReader.readAsDataURL(fileObject)的
    FileReader.result
    。它会产生无用的开销和压缩延迟,需要在服务器端执行解压缩步骤,但很容易在Javascript中作为字符串进行操作
  • 非标准且
    sendAsBinary()
    文件读取器的
    FileReader.result
    文件读取器.readAsBinaryString(fileObject)
  • 声明:

    发送二进制内容(如文件上载)的最佳方式是使用 ArrayBuffers或Blob与send()方法结合使用。但是, 如果要发送可字符串化的原始数据,请使用sendAsBinary()命令 方法,或StringView(非本机)类型的数组超类


    在支持它的浏览器中,最好的方法是将文件作为Blob发送,或者如果需要多部分表单,则使用FormData。这不需要文件读取器。这比尝试读取数据更简单、更高效

    如果您特别希望将其作为
    多部分/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);
    
    您也可以直接发送数据,而不是使用
    多部分/表单数据
    。请参阅。当然,这也需要服务器端更改

    // 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);
    

    有关浏览器支持,请参阅:(大多数浏览器,包括IE 10+。

    在正常工作时,保存在服务器上的文件版本是Base64编码的(应该是这样)。是否无法将其作为二进制数据传输,而不是Base64编码的(即,好像是使用正常的
    字段上载的)如果服务器上有PHP,则可以在存储(文件)之前对其进行base64_解码。没有-没有安全的方法通过http传输原始二进制数据。使用readAsDataURL可以在服务器上实现这一点,通过PHP的base64_解码将其运行回来(我们实际上使用的是Python,但PHP是一个很好的测试)我得到的仍然不是原始的二进制数据,也不是有效的映像=(@O,我的坏!在服务器上,您必须将base64字符串除以“,”并且只存储第二部分-这样mime类型将不会与实际文件内容一起存储。不,这是不高效的。这将增加文件大小137%,并造成服务器开销。但是没有其他方法支持F***IEI很抱歉再次挖掘此内容,只想添加这可能是发送二进制数据(等PDF文件)的最简单方法通过
    FileReader.readAsDataURL
    onload
    处理程序,而不是仅仅发送
    event.target.result
    (这不是干净的base64编码字符串),首先使用一些类似于
    event.target.result=event.target.result.match(/,(.*)/)的正则表达式来清理它[1]
    并将真实的base64发送到服务器进行解码。由于任何人都可以编辑MDN,我可能不会将其用作源代码。@user1299518,最好使用
    event.target.result.split(“,”),2)[1]
    ,而不是
    match
    @kriWebdev:在建议的选项中,您提到需要单独发送()。为什么?建议的方法对
    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);
    
    // 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);