JavaScript文件处理第二部分:文件读取

在我的前一篇blog中,我介绍了在JavaScript中如何使用文件,具体重点放在如何获得File对象。只有当用户通过上传或者拖拽的方式上传了文件,这些对象才拥有文件的元数据。一旦你有了这些文件,下一步就是从这些文件中读取数据。

前面的话

  不能直接访问用户计算机中的文件,一直都是Web应用开发中的一大障碍。2000年以前,处理文件的唯一方式就是在表单中加入<input
type=”file”>字段,仅此而已。FileAPI(文件API)的宗旨是为Web开发人员提供一种安全的方式,以便在客户端访问用户计算机中的文件,并更好地对这些文件执行操作。本文将详细介绍文件File
API

  [注意]IE9-浏览器不支持

 

上传我们一般都是用“input[type=file]”控件。当你用此控件时,你就授权了网页和服务器访问对应的文件,就可以得到File对象。

FileReader 类型

FileReader类型有一个单一的工作,就是从一个文件中读取数据并存储在一个JavaScript变量中。它的API有意设计得与XMLHttpRequest相同,因为它们都是从一个外部资源(浏览器之外)加载数据。读操作是异步的,这样不会使浏览器堵塞。

FileReader可以创建多种格式来表示文件的数据,而当读取文件时返回的格式是必须的。读取操作是通过调用下面任一方法来完成的:

  • readAsText() – 使用纯文本的形式返回文件内容
  • readAsBinaryString() –
    使用加密二进制数据字符串的形式来返回文件内容(该方法已废弃,请使用readAsArrayBuffer()代替)
  • readAsArrayBuffer() –
    使用ArrayBuffer的形式来返回文件内容(对二进制数据比如图像文件有用)
  • readAsDataURL() – 使用数据URL的形式返回文件内容

像XHR对象的send方法会发起一个Http请求一样,上面的每个方法都会启动一个文件读取。就这一点来说,在开始读取之前,你必须监听load事件,event.target.result总是返回读取的结果。例如:

var reader = new FileReader();
reader.onload = function(event) {
    var contents = event.target.result;
    console.log("File contents: " + contents);
};

reader.onerror = function(event) {
    console.error("File could not be read! Code " + event.target.error.code);
};

reader.readAsText(file);

在这个例子中,我们简单地读取文件内容,并将内容以纯文本的形式输出到console。当文件被成功读取时会调用onload操作,而因为某些原因无法读取时会调用onerror操作。在事件处理器中可以通过event.target来获得FileReader实例,而且它推荐这样使用,而不是直接使用reader变量。result属性包含读取成功时的文件内容和读取失败时的错误信息。

File

  File
API在表单中的文件输入字段的基础上,又添加了一些直接访问文件信息的接口。HTML5在DOM中为文件输入元素添加了一个files集合。在通过文件输入字段选择了一或多个文件时,files集合中将包含一组File对象,每个File对象对应着一个文件。每个File对象都有下列只读属性

  name:本地文件系统中的文件名

  size:文件的字节大小

  type:字符串,文件的MIME类型

  lastModifiedDate:字符串,文件上一次被修改的时间

  通过侦听change事件并读取files集合就可以知道选择的每个文件的信息

<input type="file" id="file1">
<div id="result"></div>
<script>
file1.onchange = function(){
    var data = file1.files[0];
    result.innerHTML = '类型:' + data.type  + '<br>大小:' + data.size + '(字节)<br>名称:' + data.name + '<br>修改时间:' + data.lastModifiedDate;
}
</script>

【隐藏文件input】

  现代浏览器支持隐藏掉默认的的文件输入框<input>元素,使用自定义的界面来充当打开文件选择对话框的按钮。实现起来很简单,只需要使用样式display:none把原本的文件输入框隐藏掉,然后在需要的时候调用它的click()方法就行了

  [注意]IE9-浏览器不支持

<input type="file" id="file1" style="display:none">
<button id="btn">按钮</button>
<div id="result"></div>
<script>
btn.onclick = function(){
    file1.click();
}
file1.onchange = function(){
    result.innerHTML = file1.files[0].name;
}
</script>

友情提示在,在Android手机webview中,是不支持上传文件的,网上说是修改Android端的代码,但我没试过,我们这边是使用客户端提供的接口来实现上传的。

读取数据URI

你可以用差不多的方法来将文件读取为一个数据URI,数据的URI(有时也叫数据URL)是个有趣的选项,比如你想要显示从磁盘上读取的图像文件,你可以用下面的代码这样做:

var reader = new FileReader();
reader.onload = function(event) {
    var dataUri = event.target.result,
        img     = document.createElement("img");

    img.src = dataUri;
    document.body.appendChild(img);
};

reader.onerror = function(event) {
    console.error("File could not be read! Code " + event.target.error.code);
};

reader.readAsDataURL(file);

这段代码简单地在页面上插入一个从磁盘上读取来的图像文件。因为这个数据URI包含了图像的所有数据,所以它可以被直接传给图像的src属性,并显示在页面上。你可以交替地加载图像和将其绘制到一个<canvas>上:

var reader = new FileReader();
reader.onload = function(event) {
    var dataUri = event.target.result,
        context = document.getElementById("mycanvas").getContext("2d"),
        img     = new Image();

    // wait until the image has been fully processed
    img.onload = function() {
        context.drawImage(img, 100, 100);
    };
    img.src = dataUri;
};

reader.onerror = function(event) {
    console.error("File could not be read! Code " + event.target.error.code);
};

reader.readAsDataURL(file);

这段代码将图像数据加载到一个新的Image对象,并将其绘制到一个画布上(宽度和长度都指定为100)。

数据URI一般用来做这个,但能用在任何类型的文件上。将文件读取为一个数据URI最普遍的用法是在web页面中快速显示文件内容。

FileReader

  File
API的功能还不止于此,通过它提供的FileReader类型甚至还可以读取文件中的数据

【构造函数】

  使用FileReader()构造函数来创建一个FileReader对象

var reader = new FileReader();

【属性】

  error:表示在读取文件时发生的错误(只读)

  readyState:表明FileReader对象的当前状态,值为状态常量中的一个(只读)

  状态常量有以下三个

常量名      值    描述
EMPTY      0    还没有加载任何数据
LOADING    1    数据正在被加载
DONE       2    已完成全部的读取请求

  result:表示读取到的文件内容,这个属性只在读取操作完成之后才有效,并且数据的格式取决于读取操作是由哪个方法发起的(只读)

【方法】

  FileReader类型实现的是一种异步文件读取机制。可以把FileReader想象成XMLHttpRequest,区别只是它读取的是文件系统,而不是远程服务器。为了读取文件中的数据,FileReader提供了如下几个方法

  abort():中止该读取操作

  readAsText(file或Blob,encoding):以纯文本形式读取File或Blob对象的内容,将读取到的文本保存在result属性中。第二个参数(可选)用于指定编码类型,默认为UTF-8

  readAsDataURL(file或Blob):读取File或Blob对象的内容,并将文件以数据URI(进行Base64编码)的形式保存在result属性中

  readAsBinaryString(file或Blob):读取File或Blob对象的内容,并将一个字符串保存在result属性中,字符串中的每个字符表示一字节

  readAsArrayBuffer(file或Blob):读取File或Blob对象的内容,并将一个包含文件内容的ArrayBuffer保存在result属性中

  [注意]IE浏览器不支持readAsBinaryString()方法

  这些读取文件的方法为灵活地处理文件数据提供了极大便利。例如,可以读取图像文件并将其保存为数据URI,以便将其显示给用户,或者为了解析方便,可以将文件读取为文本形式

【事件】

  由于读取过程是异步的,因此FileReader也提供了几个事件

  onabort:当读取操作被中止时调用

  onerror:当读取操作发生错误时调用

  onload:当读取操作成功完成时调用

  onloadend:当读取操作完成时调用,不管是成功还是失败。该处理程序在onload或者onerror之后调用

  onloadstart:当读取操作将要开始之前调用

  onprogress:在读取数据过程中周期性调用

  在正常情况下,读取文件时,首先触发loadstart事件,此时的readyState为1,result为空

  接着,每过50ms左右,就会触发一次progress事件,通过事件对象可以获得与XHR的progress事件相同的信息(属性):lengthComputable、loaded和total。另外,尽管可能没有包含全部数据,但每次progress事件中都可以通过FileReader的result属性读取到文件内容,readyState仍然是1

  当文件读取完成时,触发load事件,此时的readyState为2,result为文件内容;如果发生了error事件,就不会发生load事件

<input type="file" id="file1">
<div id="result"></div>
<script>
/*
[loadstart]readyState:1;result:
[progress]readyState:1;result:h3{color: #F44336;}
[load]readyState:2;result:h3{color: #F44336;}
[loadend]readyState:2;result:h3{color: #F44336;}
*/
file1.onchange = function(){
    var reader = new FileReader();
    reader.readAsText(file1.files[0]);
    reader.onloadstart = function(e){
        console.log('[loadstart]readyState:' + reader.readyState + ';result:' + reader.result);
    }
    reader.onload = function(e){
        console.log('[load]readyState:' + reader.readyState + ';result:' + reader.result);
    }
    reader.onloadend = function(e){
        console.log('[loadend]readyState:' + reader.readyState + ';result:' + reader.result);
    }
    reader.onprogress = function(e){
        console.log('[progress]readyState:' + reader.readyState + ';result:' + reader.result);
    }
}
</script>

  由于种种原因无法读取文件,就会触发error事件。触发error事件时,相关的信息将保存到FileReader的error属性中。这个属性中将保存一个对象,该对象只有一个属性code,即错误码。这个错误码是1表示未找到文件,是2表示安全性错误,是3表示读取中断,是4表示文件不可读,是5表示编码错误

reader.onerror = function(){
    output.innerHTML = "Could not read file, error code is " + reader.error.code;
}; 

  如果想中断读取过程,可以调用abort()方法,这样就会触发abort事件

  在触发load、error或abort事件后,会触发另一个事件loadend。loadend事件发生就意味着已经读取完整个文件,或者读取时发生了错误,或者读取过程被中断

 

 

读取ArrayBuffers

ArrayBuffer类型[1]最初是作为WebGL的一部分被引进的。一个Arraybuffer代表一个有限的字节数,可以用来存储任意大小的数字。读取一个ArrayBuffer数据的方式需要一个特定的视图,比如Int8Array是将其中的字节处理为一个有符号的8位整数集合,而Float32Array是将其中的字节处理为一个32位浮点数的集合。这些称为类型数组[2],这样可以强制你工作在一个特定的数字类型上,而不是包含任意类型的数据(像传统的数组)。

当处理二进制文件时你可以优先使用ArrayBuffer,这样对数据可以有更细粒度的控制。要解释关于ArrayBuffer的所有ins和outs已经超出本篇blog的范围,你只需要知道在你需要的时候可以很容易地将一个文件读取为一个ArrayBuffer就可以了。你可以直接传一个ArrayBuffer到一个XHR对象的send()方法,发送原始数据到服务器(你会在服务器的请求中读取这个数据去重建文件),只要你的浏览器完全支持XMLHttpRequest
Level 2[3](大部分最新的浏览器,包括IE10和Opera12都支持)。

缩略图

  使用FileReader对象的readAsDataURL()方法完成对文件的读取,再通过File对象的type属性筛选出图片

<img id="uploadPreview" style="width: 100px; height: 100px;" src="data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%3F%3E%0A%3Csvg%20width%3D%22153%22%20height%3D%22153%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%20%3Cg%3E%0A%20%20%3Ctitle%3ENo%20image%3C/title%3E%0A%20%20%3Crect%20id%3D%22externRect%22%20height%3D%22150%22%20width%3D%22150%22%20y%3D%221.5%22%20x%3D%221.500024%22%20stroke-width%3D%223%22%20stroke%3D%22%23666666%22%20fill%3D%22%23e1e1e1%22/%3E%0A%20%20%3Ctext%20transform%3D%22matrix%286.66667%2C%200%2C%200%2C%206.66667%2C%20-960.5%2C%20-1099.33%29%22%20xml%3Aspace%3D%22preserve%22%20text-anchor%3D%22middle%22%20font-family%3D%22Fantasy%22%20font-size%3D%2214%22%20id%3D%22questionMark%22%20y%3D%22181.249569%22%20x%3D%22155.549819%22%20stroke-width%3D%220%22%20stroke%3D%22%23666666%22%20fill%3D%22%23000000%22%3E%3F%3C/text%3E%0A%20%3C/g%3E%0A%3C/svg%3E" alt="Image preview" />
<input type="file" id="file1" style="display:none">
<button id="btn">选择图片</button>

<script>
btn.onclick = function(){
    file1.click();
}
file1.onchange = function(){
    var file = file1.files[0];
    //如果一个文件被选中
    if(file){
        //一张图片被选中
        if (/image/.test(file.type)){
            var reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = function(){
                uploadPreview.src = reader.result;
                msgName.innerHTML = file.name;
            }
        //其他格式文件被选中
        } else {
            alert("You must select a valid image file!");
        }                
    }    
}
</script>

下面的示例代码可以在这里查看到。

Blob URL

  使用Blob
URL,也可以用来显示缩略图

<input id="file1" type="file" accept="image/gif,image/jpeg,image/jpg,image/png,image/x-icon"  style="display:none">
<button id="btn">选择图片</button>
<div id="fileList"></div>
<script>
btn.onclick = function(){file1.click();}
//保存图片的名称
var dataArr = [];
file1.onchange = function(){
    var file = file1.files[0];
    //如果一个文件被选中
    if(file){
        var name = file.name;
        var id = name.split('.').join('_');
        //检测图片是否已经被存储过
        if(dataArr.indexOf(id) > -1){
            //将保存过的图片转移到最下方
            fileList.appendChild(document.getElementById(id));
        }else{
            if(/image/.test(file.type)){
                dataArr.push(id);
                var img = document.createElement('img');
                img.onload = function(){
                    URL.revokeObjectURL(img.src);
                }
                img.src= URL.createObjectURL(file);
                img.height = 60;
                var oDiv = document.createElement('div');
                oDiv.id = id;
                var oSpan = document.createElement('span');
                oSpan.innerHTML = name + ":" + file.size + " bytes";
                oDiv.appendChild(img);
                oDiv.appendChild(oSpan);
                fileList.appendChild(oDiv);                
            }
        }
    }    
}
</script>

 

文件内容

  readAsText()可以以字符串形式读取并显示文件内容

<input id="file1" type="file"  style="display:none">
<button id="btn">选择文件</button>
<div id="fileData" style="border:1px solid black;width:300px;overflow:auto"></div>
<script>
btn.onclick = function(){file1.click();}
file1.onchange = function(){
    var file = file1.files[0];
    //如果一个文件被选中
    if(file){
        var reader = new FileReader();
        reader.readAsText(file);
        reader.onload = function(){
            fileData.innerHTML = reader.result;
        }
    }         
}
</script>

一、accept属性

 

该属性表明了服务器端可接受的文件类型,可以限制你手机选择相关的文件,如果限制多个,可以用逗号分割,下面的代码就表示只能选择图片与音频相关的文件:

 

<input accept="image/*,audio/*" type="file"/>

 

图片 1

 

在移动端,点击后会让你选择拍照或相册,还是蛮高大上的。下图是UC浏览器中:

 

图片 2

 

 

 

拖放选择

  围绕读取文件信息,结合使用HTML5拖放API和文件API,能够创造出令人瞩目的用户界面:在页面上创建了自定义的放置目标之后,你可以从桌面上把文件拖放到该目标。与拖放一张图片或者一个链接类似,从桌面上把文件拖放到浏览器中也会触发drop事件。而且可以在event.dataTransfer.files中读取到被放置的文件,当然此时它是一个File对象,与通过文件输入字段取得的File对象一样

  [注意]IE9-浏览器不支持event.dataTransfer

  从电脑上选择一个图片文件,并拖放到网页中指定区域,图片缩略图将显示到网页上

<div id="targetArea" style="height:50px;line-height:50px;width:210px;background:lightblue;">请将图片文件拖放到该区域内</div>
<div id="result"></div>
<script>
function addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,handler,false);
    }else{
        target.attachEvent('on'+type,function(event){
            return handler.call(target,event);
        });
    }
}
function preventDefault(e){
    e = e || event;
    if(e.preventDefault){
        e.preventDefault();
    }else{
        e.returnValue = false;
    }
}
addEvent(document,'dragover',preventDefault);
addEvent(document,'drop',preventDefault);
addEvent(targetArea,'dragenter',preventDefault);
addEvent(targetArea,'dragover',preventDefault);
addEvent(targetArea,'dragleave',preventDefault);
addEvent(targetArea,'drop',preventDefault);
targetArea.ondragenter = function(e){this.style.outline = "1px solid black";}
targetArea.ondragleave = function(e){this.style.outline = "";}
targetArea.ondrop = function(e){
    e = e || event;
    this.style.outline = "";
    var file = e.dataTransfer.files[0];
    if(file){
        //一张图片被选中
        if (/image/.test(file.type)){
            var reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = function(){
                var oDiv = document.createElement('div');
                oDiv.id = file.name.split('.').join('_')
                var img = new Image();
                img.src = reader.result;
                img.height = 60;
                var oName = document.createElement('span');
                oName.innerHTML = file.name;
                var oDel = document.createElement('button');
                oDel.innerHTML = '删除';
                oDel.onclick = function(){
                    result.removeChild(oDiv);
                }               
                oDiv.appendChild(img);
                oDiv.appendChild(oName);
                oDiv.appendChild(oDel);
                result.appendChild(oDiv);
            }
        //其他格式文件被选中
        } else {
            alert("You must select a valid image file!");
        }          
    }
}
</script>

二、change事件

 

一般选择文件都会使用“change”事件,下面的代码就是绑定了change事件,弹出文件大小:

 

var upload = document.getElementById('upload');
upload.addEventListener('change', function() {
  var file = upload.files[0];
  alert(file.size);
}, false);

 

1)
有些手机浏览器在点击的时候,会弹出键盘选择,我用onfocus=”this.blur()”,来强制失去焦点。

 

<input type="file" id="upload" onfocus="this.blur()"/>

 

2)
当选择过一次后,再次选择同一个文件,“change”事件不会触发,因为value没有改变,在网上看到个方法,我还没有在实际项目中使用,兼容性有待考证。

 

使用“Node.cloneNode”复制上传元素,再用“Node.replaceChild”替换节点。

 

这里注意下:克隆一个元素节点会拷贝它所有的属性以及属性值,但不会拷贝那些使用addEventListener()方法或者node.onclick
= fn用JavaScript动态绑定的事件。

 

 

upload.addEventListener('change', function() {
  var upload = document.getElementById('upload'); //每次要动态获取
  var file = upload.files[0];
  console.log(file.size);

  //解决上传相同文件不触发onchange事件  
  var clone = upload.cloneNode(true);
  clone.onchange = arguments.callee; //克隆不会复制动态绑定事件
  clone.value = '';
  upload.parentNode.replaceChild(clone, upload);
}, false);

 

 

 

 

文件进度

  使用onprogress事件的loaded和total属性,可以实现文件进度显示

<input id="file1" type="file"  style="display:none">
<button id="btn">选择文件</button>
<div id="fileData"></div>
<script>
btn.onclick = function(){file1.click();}
file1.onchange = function(){
    var file = file1.files[0];
    //如果一个文件被选中
    if(file){
        var reader = new FileReader();
        reader.readAsText(file);
        reader.onprogress = function(e){
            e = e || event;
            fileData.innerHTML = '文件进度为:' + e.loaded + '/' + e.total;
        }
    }         
}
</script>

三、File对象

 

用户所选择的文件都存储在了一个FileList对象上,其中每个文件都对应了一个File对象

 

File对象负责处理那些以文件形式存在的二进制数据,也就是操作本地文件。

 

File对象是Blob【下面会提到】的特殊类型,即大块的二进制数据,File对象的尺寸及类型等属性都继承自Blob。

 

1)File对象可以通过3种方式获取:

 

  1. <input>元素上选择文件后返回的FileList对象中的成员

 

2.
拖放操作【Drag或Drop】生成的 DataTransfer对象内files属性中的成员

 

3. HTMLCanvasElement上执行mozGetAsFile()方法后的返回结果

 

document.getElementById('upload').files[0]//选取第一个文件对象

 

2)File对象有9个属性,这里就只介绍3个:

 

1. name:当前File对象所引用文件的文件名,不包括路径,只读。

 

2. size:文件大小,单位为字节,只读的64位整数.

 

3. type:MIME类型,只读字符串,如果类型未知,则返回null。有些移动端的浏览器明明选择了图片,返回的却是null,非常坑。

 

还有3个非标准的方法:getAsBinary()、getAsDataURL()和getAsText(in
DOMString encoding)。

 

这3个方法现在已经过时,现在用FileReader对象中的方法来取代。

 

 

 

文件上传

方法一:使用表单提交实现文件上传

  文件上传最基本的方法是使用HTML表单选择本地文件进行上传,在form表单中通过<input
type=”file”>标记选择本地文件。并且,必须在<form>元素中将enctype设置为”multipart/form-data”,将method设置为”post”

  另外,需要在<form>表单中设置一个hidden类型的input框,其中name值为MAX_FILE_SIZE的隐藏值域,通过设置其value值限制上传文件的大小

<form action="pp.php" method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="1000000">
    <input type="file" name="file1">
    <button>上传文件</button>
</form>

方法二:使用FormData实现文件上传

  创建一个FormData()对象,通过它调用append()方法并传入相应的File对象作为参数。然后,再把FormData对象传递给XHR的send()方法

  [注意]IE9-浏览器不支持使用FormData()上传文件

<input type="file" name="file1" id="file1">
<div id="result"></div>
<script>
var oFile = document.getElementById('file1');
oFile.onchange = function(e){
    //创建xhr对象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    };
    var data = new FormData();
    data.append('file',oFile.files[0])
    //异步接受响应
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //实际操作
                result.innerHTML = xhr.responseText;
            }
        }
    }
    //发送请求
    xhr.open('post','pp.php',true);
    xhr.send(data);
}
</script>

方法三:使用File API实现文件上传

  通过File API传送二进制文件

  [注意]IE9-浏览器不支持

<input type="file" name="file1" id="file1">
<div id="result"></div>
<script>
var oFile = document.getElementById('file1');
oFile.onchange = function(e){
    //创建xhr对象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    };
    var data = oFile.files[0];
    //异步接受响应
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //实际操作
                result.innerHTML = xhr.responseText;
            }
        }
    }
    //发送请求
    xhr.open('post','pp.php',true);
    xhr.setRequestHeader("content-type",data.type);
    xhr.send(data);
}
</script>

<?php
$file = 'photo/test1.jpg';
touch($file);

function binary_to_file($file){
    $content = $GLOBALS['HTTP_RAW_POST_DATA'];  // 需要php.ini设置
    if(empty($content)){
        $content = file_get_contents('php://input'); //不需要php.ini设置,内存压力小
    }
    $ret = file_put_contents($file, $content, true);
    return $ret;
};echo '文件上传成功!';
?>

 

四、FileReader

 

web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可以使用File对象或者Blob对象来指定所要处理的文件或数据。

 

1) readAsArrayBuffer)():在返回的result属性中将包含一个ArrayBuffer对象【缓冲数组,是一种用于呈现通用、固定长度的二进制数据的类型】以表示所读取文件的内容

 

Blob可以“append”,ArrayBuffer数据。ArrayBuffer存在的意义就是作为数据源提前写入在内存中,就是提前钉死在某个区域,长度也固定。

 

2) readAsBinaryString)():result属性中将包含所读取文件的原始二进制数据

 

3) readAsDataURL)():result属性中将包含一个data:
URL格式的字符串以表示所读取文件的内容

 

4) readAsText)():result属性中将包含一个字符串以表示所读取的文件内容

 

下面的代码是获取data:URL,可以将返回的result内容赋值给img的src,用于预览等操作。

 

 

var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e) {
  var img = new Image();
  img.src = this.result;
  console.log(this.result);
};

 

 

console.log(this.result)内容如下:

 

图片 3

 

 

 

删除文件

  最后,提一个小知识点,使用<input
type=”file>控件选择文件后,如何删除文件呢?一般地,有两种方法。一种是使用form表单的reset()方法,重置表单;另一种是将<input
type=”file>控件的value值置空,但第二种方法IE10-浏览器不支持

<form id="myForm">
  <input type="file" id="myFile">
</form>
<button id="btn1">删除文件方法1</button>
<button id="btn2">删除文件方法2</button>
<script>
var myFile = document.getElementById('myFile');
var myForm = document.getElementById('myForm');
btn1.onclick = function(){
  myFile.value = '';
}
btn2.onclick = function(){
  myForm.reset();
}
</script>

五、URL对象

 

URL对象是硬盘上指向文件的URL。上面的例子中获取图片的引用,通过读取data
URI,data URI是个一大串的字符。

 

图片原本就在硬盘上,还要转换成另一个格式再用,有点绕了,完全可以直接引用文件的URL,下面是两个方法:

 

1)
URL.createObjectURL():接收一个文件的引用(File或Blob对象)返回一个URL对象

 

2)
URL.revokeObjectURL():销毁创建的URL

 

 

var url = URL.createObjectURL(file);
var img = new Image();
img.src = url;
img.onload = function(e) {
  window.URL.revokeObjectURL(this.src); //销毁
}
console.log(url);

 

 

console.log(url)内容如下:

 

图片 4

 

在移动端需要做个兼容性判断:

 

window.URL = window.URL || window.webkitURL;

 

 

 

六、Blob对象

 

Blob(binary
large
object)对象代表了一段二进制数据,就是一个包含只读原始数据的类文件对象。

 

File接口基于Blob,继承了Blob的功能,并且扩展支持了用户计算机上的本地文件。

 

1)创建Blob对象的4种方法:

 

  1. 调用Blob构造函数

 

  1. 使用一个已有Blob对象上的slice()方法切出另一个Blob对象

 

  1. 调用canvas对象上的toBlob方法

 

4. 过气的方法,通过BlobBuilder接口创建,但兼容性不好,并且现有的BlobBuilder实现都是带前缀的

 

 

 

2)利用Blob对象,生成可下载文件

 

var blob = new Blob(["pwstrick"]);//数组中添加DOMString对象
var a = document.createElement("a");
a.href = URL.createObjectURL(blob);//创建URL对象
a.download = "test.txt";//HTML5新属性
a.textContent = "test";            
document.getElementsByTagName('body')[0].appendChild(a);

 

生成一个“a”标签,并且点击这个链接,可以下载一个txt文本,内容是“pwstrick”。

 

 

 

3)通过slice方法,将二进制数据按照字节分块,返回一个新的Blob对象

 

 

upload.addEventListener('change', function() {
  var upload = document.getElementById('upload'); //每次要动态获取
  var file = upload.files[0];
  var start = 0;
  var chunk = 1024 * 10; //10KB
  var end = start + chunk;
  var size = file.size;
  while (start < size) {
    segment(file, start, end);
    start = end;
    end = start + chunk;
    if (end > size) {
      end = size;
    }
  }
}, false);

function segment(file, start, end) {
  var reader = new FileReader();
  reader.onload = function(evt) {
    console.log(['Read bytes: ', start, ' - ', end].join(''));
  };
  var blob = file.slice(start, end);
  reader.readAsBinaryString(blob);
}

 

 

 

 

七、formData

 

XMLHttpRequest Level
2添加了一个新的接口FormData。

 

利用FormData对象,可以使用键值对来模拟一个完整的表单,然后使用XMLHttpRequest发送这个”表单”。

 

使用FormData的最大优点就是我们可以异步上传一个二进制文件。

 

 

  var formData = new FormData();
  formData.append("name", "value");//普通键值对
  formData.append("blob", blob); //传递一个blob对象
  formData.append("file", file); //传递一个file对象
  var oReq = new XMLHttpRequest();
  oReq.open("POST", "http://xx.com");
  oReq.send(formData);

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注