重新认识 File API

File & FileReader & FileList & Blob & URL scheme 这几个方法或者说是“接口”都是一同被定义在了 W3C File API 的规范之中。

如果要画一张关系图的话,按照理解应该是这样的:

Blob

最初被 Google 使用的时候叫做 Binary Large Object ,表示不可变的原始二进制数据

参数

new Blob(blobParts : Array, [blobPropertyBag : Object]) : Blob
                             blobPropertyBag : {
                                 type	String	A valid mime type such as 'text/plain'
                                 endings	String	Must be either 'transparent' or 'native'
                             }

Blob 第一个参数可以接受的数据类型有:

第二个参数可以接受

  • type 通常我们会传一些媒体类型,比如指定 mp3, png格式
  • endings 只能传 ‘transparent’ 或者 ‘native’
var blob = new Blob(['foo', 'bar']);

console.log('size=' + blob.size);
console.log('type=' + blob.type);

var testEndings = function(string, endings) {
  var blob = new Blob([string], { type: 'plain/text',
                                  endings: endings });
  var reader = new FileReader();
  reader.onload = function(event){
    console.log(endings + ' of ' + JSON.stringify(string) + 
                ' => ' + JSON.stringify(reader.result));
  };
  reader.readAsText(blob);
};

testEndings('foo\nbar',   'native');
testEndings('foo\r\nbar', 'native');
testEndings('foo\nbar',   'transparent');
testEndings('foo\r\nbar', 'transparent');



size=6
type=
native of "foo\nbar" => "foo\nbar"
native of "foo\r\nbar" => "foo\nbar"
transparent of "foo\nbar" => "foo\nbar"
transparent of "foo\r\nbar" => "foo\r\nbar"

属性:

  • type 只读属性
  • size 只读属性
var blob = new Blob(['foo', 'bar'], { type: 'plain/text',
                                      endings: 'native' });

console.log(blob.type); // plain/text


var blob = new Blob(['foo', 'bar'], { type: 'plain/text',
                                      endings: 'native' });

console.log(blob.size); // 6

方法

  • slice
  • stream
  • text
  • arrayBuffer

slice 顾名思义,和数组的 slice 差不多,传入起始位置 start 和终止位置 end,截取的内容是从 start ~ end – 1 区间的内容,如果传入负数和超过长度的值,则会根据具体的规则进行调整,不做赘述,可以看具体规范定义的。

var blob = new Blob(['foo', 'bar'], { type: 'plain/text',
                                      endings: 'native' });
console.log('blob size:', blob.size); // blob size: 6
console.log('blob type:', blob.type); // blob type: plain/text

var copy = blob.slice()
console.log('copy size:', copy.size); // copy size: 6
console.log('copy type:', copy.type); // copy type: 

var slice = blob.slice(1, 4, 'foo-type')
console.log('slice size:', slice.size); // slice size: 3
console.log('slice type:', slice.type); // slice type: foo-type

steam ,arrayBuffer,和 text 在兼容性上比较差,,steam 是用 ‘流’ 的方式返回,text 方法返回 promise, then 方法中可以拿到完整的 blob 内容。

var blob = new Blob(['abcd'])
blob.text().then(res => {
    console.log(res) // abcd
})

兼容性:

File

File 对象继承自 Blob,并增加了几个属性用于描述该对象。

new File(fileParts : Array, name : String, [filePropertyBag : Object]) : File
filePropertyBag : {
    type	String	A valid mime type such as 'text/plain'
    endings	String	Must be either 'transparent' or 'native'
    lastModified long
}

File 第一个参数可以接受的数据类型有:

第二参数:name, 指定文件名

第三参数: 接收一个对象, 比 Blob 多了一个字段, lastModified 用来指定修改时间。

构造一个 File 对象:

var d = new Date(2020, 08, 01, 16, 23, 45, 600);
var generatedFile = new File(["Rough Draft ...."], "Draft1.txt", {type: "text/plain", lastModified: d})

属性

  • name 只读
  • lastModified 只读

FileList

一个包含所有 File 文件集合的 list。可以通过在 file 标签上指定 multiple 来让用户可以多选文件。通过类似数组下标的方式获取对应的 File 对象。

<input id='file-input' type='file' multiple>
<script>
  var fileInput = document.getElementById('file-input');
  fileInput.addEventListener('change', function(event) {
    var input = event.target;

    for (var i = 0; i < input.files.length; i++) {
      console.log(input.files[i].name);
    }
  });
</script>

FileReader

提供异步读取方法,可以通过事件监听的方式来异步的获取文件的数据,可以读取 File 和 Blob 对象的内容。

写了一个 Demo 用于读取本地文件,并展示读取进度条的例子🌰:

See the Pen file read progress by hjoker (@hjoker) on CodePen.

由于本质上是读取文件并加载到内存中,所以不推荐直接读取大文件,因为这样会导致浏览器占用过多内存,即便浏览器内部会适时的释放内存,但是依旧会碰到无响应的后果。

FileReader 有一个方法 readAsDataURL,它可以自动帮你生成对应文件的 Base64 字符串,并在 onload 时候触发,可以从 result 属性中获取到。

再看一眼下面这张图是不是和 XMLHttpRequest 很类似?有 onload error 一系列方法。同样需要注意,载入过大的文件尺寸会影响浏览器计算 Base64 的速度

See the Pen FileReader get Base64 by hjoker (@hjoker) on CodePen.

列一下 state 的几种状态。 初始状态是 Empty 也就是 0。

var reader = new FileReader()
> reader.readyState
0
> FileReader.EMPTY
0
> FileReader.LOADING
1
> FileReader.DONE
2

See the Pen FileReader state by hjoker (@hjoker) on CodePen.

触发事件:

  • onloadstart
  • onprogress
  • onabort
  • onerror
  • onload
  • onloadend

方法:

  • readAsBinaryString(blob)
  • readAsArrayBuffer(blob) —— 将数据读取为二进制格式的 ArrayBuffer
  • readAsText(blob, [encoding]) —— 将数据读取为给定编码(默认为 utf-8 编码)的文本字符串。
  • readAsDataURL(blob) —— 读取二进制数据,并将其编码为 base64 的 data url

参考出处: