1. 简介
本节为说明性内容。
Web 应用程序应具备操作尽可能多的用户输入类型的能力,包括用户可能希望上传到远程服务器或在富 Web 应用程序中操作的文件。 本规范定义了文件的基本表示、文件列表、文件访问产生的错误以及读取文件的编程方式。 此外,本规范还定义了一个表示“原始数据”的接口,该接口可以在符合标准的用户代理的主线程上异步处理。 本规范中定义的接口和 API 可与 Web 平台上公开的其他接口和 API 一起使用。
File
接口代表通常从底层文件系统获取的文件数据,
Blob
接口
(“二进制大对象” - 最初由 Google Gears 引入到 Web API 中)
表示不可变的原始数据。File
或 Blob
的读取应在主线程上异步进行,
线程化 Web 应用程序中可使用可选的同步 API。
使用异步 API 读取文件可防止阻塞并避免用户代理的主线程“冻结”界面。
本规范定义了基于 事件模型 的异步 API,用于读取和访问 File
或 Blob
的数据。
FileReader
对象提供异步读取方法以访问文件的数据,
通过事件处理器内容属性和事件的触发来进行读取。
使用事件和事件处理器允许不同的代码块监视 读取进度(这在远程驱动器或挂载的驱动器中尤为有用,因为文件访问性能可能与本地驱动器不同),
以及在读取文件时可能出现的错误情况。
下面的示例将更具说明性。
function startRead() { // 通过 DOM 获取 input 元素 var file= document. getElementById( 'file' ). files[ 0 ]; if ( file){ getAsText( file); } } function getAsText( readFile) { var reader= new FileReader(); // 将文件作为 UTF-16 读取到内存中 reader. readAsText( readFile, "UTF-16" ); // 处理进度、成功和错误 reader. onprogress= updateProgress; reader. onload= loaded; reader. onerror= errorHandler; } function updateProgress( evt) { if ( evt. lengthComputable) { // evt.loaded 和 evt.total 是 ProgressEvent 属性 var loaded= ( evt. loaded/ evt. total); if ( loaded< 1 ) { // 增加进度条长度 // style.width = (loaded * 200) + "px"; } } } function loaded( evt) { // 获取读取的文件数据 var fileString= evt. target. result; // 处理 UTF-16 文件转储 if ( utils. regexp. isChinese( fileString)) { // 中文字符 + 名称验证 } else { // 运行其他字符集测试 } // xhr.send(fileString) } function errorHandler( evt) { if ( evt. target. error. name== "NotReadableError" ) { // 无法读取文件 } }
2. 术语和算法
当本规范提到 终止算法 时,用户代理必须在完成当前步骤后终止该算法。
本规范中定义的异步 读取方法 可能在相关算法终止之前返回,
并且可以通过调用 abort()
来终止。
本规范中的算法和步骤使用以下数学运算:
-
max(a,b) 返回 a 和 b 中的最大值, 始终在 WebIDL 中定义的整数上执行 [WebIDL]; 在 max(6,4) 的情况下,结果是 6。 此操作也在 ECMAScript 中定义 [ECMA-262]。
-
min(a,b) 返回 a 和 b 中的最小值, 始终在 WebIDL 中定义的整数上执行 [WebIDL]; 在 min(6,4) 的情况下,结果是 4。 此操作也在 ECMAScript 中定义 [ECMA-262]。
-
数学比较运算符如 <(小于),≤(小于等于)和 >(大于) 与 ECMAScript 相同 [ECMA-262]。
本规范使用的术语 Unix 纪元
指的是 1970 年 1 月 1 日 00:00:00 UTC 的时间
(或 1970-01-01T00:00:00Z ISO 8601);
这是 ECMA-262 中概念上 "0
" 的时间 [ECMA-262]。
Blob
blob,start,end 和 contentType,
用于执行以下步骤,并返回一个新的 Blob
,包含从
start 参数到(但不包括)end 参数的字节。算法步骤如下:
-
令 originalSize 为 blob 的
大小
。 -
start 参数(如果非空)表示 分割 Blob 调用的起始点, 必须将其视为字节顺序位置,第零位表示第一个字节。用户代理必须按照以下步骤规范化 start:
- 如果 start 为 null,令 relativeStart 为 0。
- 如果 start 为负数,令 relativeStart 为
max((originalSize + start), 0)
。 - 否则,令 relativeStart 为
min(start, originalSize)
。
-
end 参数(如果非空)表示 分割 Blob 调用的结束点。用户代理必须按照以下步骤规范化 end:
- 如果 end 为 null,令 relativeEnd 为 originalSize。
- 如果 end 为负数,令 relativeEnd 为
max((originalSize + end), 0)
。 - 否则,令 relativeEnd 为
min(end, originalSize)
。
-
contentType 参数(如果非空),用于设置表示
Blob
媒体类型的 ASCII 编码小写字符串。 用户代理必须按照以下步骤规范化 contentType:- 如果 contentType 为 null,令 relativeContentType 为空字符串。
-
否则,令 relativeContentType 为 contentType,并执行以下子步骤:
-
如果 relativeContentType 包含 U+0020 到 U+007E 之外的任何字符,则将 relativeContentType 设为空字符串,并退出这些子步骤。
-
将 relativeContentType 中的每个字符转换为 ASCII 小写字母。
-
-
令 span 为
max((relativeEnd - relativeStart), 0)
。 -
返回一个新的
Blob
对象 S,其特征如下:
3. Blob 接口与二进制数据
Blob
对象
指的是一个 字节 序列,
并且有一个 大小
属性,表示字节序列中的字节总数,
以及一个 类型
属性,
这是一个小写的 ASCII 编码字符串,表示该 字节 序列的媒体类型。
每个 Blob
必须
有一个内部 快照状态,
如果存在底层存储,则该状态必须最初设置为底层存储的状态。
有关 快照状态 的进一步规范定义可以在 File
中找到。
[Exposed =(Window ,Worker ),Serializable ]interface {
Blob (
constructor optional sequence <BlobPart >blobParts ,optional BlobPropertyBag = {});
options readonly attribute unsigned long long size ;readonly attribute DOMString type ; // slice Blob into byte-ranged chunksBlob slice (optional [Clamp ]long long ,
start optional [Clamp ]long long ,
end optional DOMString ); // read from the Blob. [
contentType NewObject ]ReadableStream stream (); [NewObject ]Promise <USVString >text (); [NewObject ]Promise <ArrayBuffer >arrayBuffer (); [NewObject ]Promise <Uint8Array >bytes (); };enum {
EndingType ,
"transparent" };
"native" dictionary {
BlobPropertyBag DOMString type = "";EndingType endings = "transparent"; };typedef (BufferSource or Blob or USVString );
BlobPart
Blob
对象
是 可序列化对象。它们的 序列化步骤,
给定 value 和 serialized,如下:
-
将 serialized.[[SnapshotState]] 设置为 value 的 快照状态。
-
将 serialized.[[ByteSequence]] 设置为 value 的底层字节序列。
它们的 反序列化步骤,给定 serialized 和 value,如下:
-
将 value 的 快照状态 设置为 serialized.[[SnapshotState]]。
-
将 value 的底层字节序列设置为 serialized.[[ByteSequence]]。
Blob
blob 具有关联的 获取流 算法,
执行以下步骤:
-
令 stream 为在 blob 的 相关 Realm 中创建的一个 新的
ReadableStream
。 -
设置 stream 以支持字节读取。
-
执行以下步骤 并行:
-
当尚未读取 blob 的所有字节时:
-
令 bytes 为从 blob 读取的 块 所产生的字节序列, 如果无法读取块,则为失败。
-
在 blob 的 相关全局对象 上,基于 全局任务队列 来执行以下步骤:
-
令 chunk 为一个新的
Uint8Array
包装一个包含 bytes 的ArrayBuffer
。如果创建ArrayBuffer
时抛出异常,则将该异常标记为 错误 并中止这些步骤。 -
入队 chunk 到 stream。
-
-
-
返回 stream。
3.1. 构造函数
Blob()
构造函数可以使用零个或多个参数进行调用。
当 Blob()
构造函数被调用时,
用户代理必须执行以下步骤:
3.1.1. 构造函数参数
Blob()
构造函数可以使用以下参数进行调用:
blobParts
序列
-
它可以包含以下任意类型的元素,并且顺序不限:
-
BufferSource
元素。 -
Blob
元素。 -
USVString
元素。
-
- 一个
可选的
BlobPropertyBag
-
它包含以下可选成员:
-
type
, 一个小写的 ASCII 编码字符串,表示Blob
的媒体类型。 有关此成员的规范条件,请参阅 § 3.1 构造函数。 -
endings
, 一个枚举,值可以为"transparent"
或"native"
。 默认情况下,此值设置为"transparent"
。 如果设置为"native"
, 则行结束符将被转换为本地格式 ,在USVString
元素中转换。
-
BlobPart
的序列
parts 和 BlobPropertyBag
options,执行以下步骤以 处理 blob 部分:
-
令 bytes 为一个空的字节序列。
-
对 parts 中的每个 element 执行以下操作:
-
如果 element 是
USVString
, 执行以下子步骤: -
如果 element 是
BufferSource
, 获取缓冲区源持有的字节副本, 并将这些字节附加到 bytes。 -
如果 element 是
Blob
, 将其表示的字节附加到 bytes。
-
-
返回 bytes。
-
令 native line ending 为 代码点 U+000A LF。
-
如果底层平台的约定是将换行符表示为回车和换行序列, 则将 native line ending 设置为 代码点 U+000D CR 后跟 代码点 U+000A LF。
-
将 result 设置为空的 字符串。
-
令 position 为 位置变量,最初指向 s 的起始位置。
-
令 token 为 收集一系列代码点的结果, 这些代码点不等于 U+000A LF 或 U+000D CR,s 中的 position 被提供给它。
-
将 token 附加到 result。
-
当 position 尚未超过 s 的结尾时:
-
如果 position 处的 代码点 等于 U+000D CR:
-
将 native line ending 附加到 result。
-
将 position 前进 1。
-
如果 position 未超过 s 的结尾,并且 position 处的代码点等于 U+000A LF, 则将 position 前进 1。
-
-
否则,如果 position 处的代码点等于 U+000A LF, 则将 position 前进 1,并将 native line ending 附加到 result。
-
令 token 为 收集一系列代码点 的结果, 这些代码点不等于 U+000A LF 或 U+000D CR,s 中的 position 被提供给它。
-
将 token 附加到 result。
-
-
返回 result。
// 创建一个新的 Blob 对象 var a= new Blob(); // 创建一个 1024 字节的 ArrayBuffer // buffer 也可以来自读取一个文件 var buffer= new ArrayBuffer( 1024 ); // 基于 buffer 创建 ArrayBufferView 对象 var shorts= new Uint16Array( buffer, 512 , 128 ); var bytes= new Uint8Array( buffer, shorts. byteOffset+ shorts. byteLength); var b= new Blob([ "foobarbazetcetc" + "birdiebirdieboo" ], { type: "text/plain;charset=utf-8" }); var c= new Blob([ b, shorts]); var a= new Blob([ b, c, bytes]); var d= new Blob([ buffer, b, c, bytes]);
3.2. 属性
size
, 类型为 unsigned long long, 只读- 返回字节序列的大小(以字节为单位)。
获取时,符合标准的用户代理必须返回可以通过
FileReader
或FileReaderSync
对象读取的字节总数, 如果Blob
没有可读取的字节,则返回 0。 type
, 类型为 DOMString, 只读-
以小写形式返回表示
Blob
的媒体类型的 ASCII 编码字符串。 获取时,用户代理必须以小写形式返回Blob
的类型作为 ASCII 编码字符串, 使其转换为 字节序列时, 它是可解析的 MIME 类型, 如果无法确定类型,则为空字符串(0 字节)。type
属性可以通过构造函数调用或slice()
调用由 Web 应用程序自行设置; 在这些情况下,此属性的进一步规范条件请参阅 § 3.1 构造函数、§ 4.1 构造函数 和 § 3.3.1 slice() 方法。 用户代理还可以确定type
的Blob
, 特别是当字节序列来自磁盘文件时; 在这种情况下,进一步的规范条件请参阅 文件类型指南。注意: 如果将表示 Blob 对象类型的 ASCII 编码字符串转换为字节序列时, 执行 解析 MIME 类型 算法没有返回失败, 则 t 类型的
Blob
被认为是 可解析的 MIME 类型。注意: 使用
type
属性会影响 打包数据 算法 ,并决定在 抓取 Blob URL 时的Content-Type
头。
3.3. 方法和参数
3.3.1. slice()
方法
slice()
方法
返回一个新的 Blob
对象,字节范围从可选的 start 参数开始,
到(但不包括)可选的 end 参数,并且具有一个 type
属性,该属性的值是可选的 contentType 参数。其操作如下:
-
令 sliceStart、sliceEnd 和 sliceContentType 为 null。
-
如果给定了 start,将 sliceStart 设置为 start。
-
如果给定了 end,将 sliceEnd 设置为 end。
-
如果给定了 contentType,将 sliceContentType 设置为 contentType。
-
返回执行 slice blob 的结果,参数为 this、sliceStart、sliceEnd 和 sliceContentType。
slice()
调用。由于 File
接口继承自 Blob
接口,因此示例基于 File
接口的使用。
// 通过 DOM 获取输入元素 var file= document. getElementById( 'file' ). files[ 0 ]; if ( file) { // 创建文件的相同副本 // 以下两个调用是等价的 var fileClone= file. slice(); var fileClone2= file. slice( 0 , file. size); // 从文件中间开始切片为一半,负数的使用 var fileChunkFromEnd= file. slice( - ( Math. round( file. size/ 2 ))); // 从文件开头开始切片为一半 var fileChunkFromStart= file. slice( 0 , Math. round( file. size/ 2 )); // 从文件开头开始切片,直到距末尾 150 字节 var fileNoMetadata= file. slice( 0 , - 150 , "application/experimental" ); }
3.3.2. stream()
方法
stream()
方法被调用时,必须返回调用 get stream 的结果,调用对象为 this。
3.3.3. text()
方法
text()
方法被调用时,必须运行以下步骤:
-
调用 get stream 的结果作为 stream,调用对象为 this。
-
调用 获取读取器 的结果作为 reader,读取自 stream。 如果抛出异常,返回一个以该异常拒绝的新 promise。
-
将 promise 作为调用 读取所有字节 的结果,读取自 stream 并使用 reader。
-
返回 promise 的结果,通过一个履约处理程序,该处理程序返回对其第一个参数运行 UTF-8 解码 的结果。
注意: 这与 readAsText()
的行为不同,
更好地与 Fetch 的 text()
行为对齐。
具体来说,该方法将始终使用 UTF-8 编码,而 FileReader
根据 blob 的类型和传入的编码名称,可能使用不同的编码。
3.3.4.
arrayBuffer()
方法
arrayBuffer()
方法被调用时,必须运行以下步骤:
-
调用 get stream 的结果作为 stream,调用对象为 this。
-
调用 获取读取器 的结果作为 reader,读取自 stream。 如果抛出异常,返回一个以该异常拒绝的新 promise。
-
将 promise 作为调用 读取所有字节 的结果,读取自 stream 并使用 reader。
-
返回通过一个履约处理程序转换 promise 的结果,该处理程序返回一个新的
ArrayBuffer
,其内容为其第一个参数。
3.3.5. bytes()
方法
bytes()
方法被调用时,必须运行以下步骤:
-
调用 get stream 的结果作为 stream,调用对象为 this。
-
调用 获取读取器 的结果作为 reader,读取自 stream。 如果抛出异常,返回一个以该异常拒绝的新 promise。
-
将 promise 作为调用 读取所有字节 的结果,读取自 stream 并使用 reader。
-
返回通过一个履约处理程序转换 promise 的结果,该处理程序返回一个新的
Uint8Array
,其包装了一个包含其第一个参数的ArrayBuffer
。
4. File 接口
File
对象是一个
Blob
对象,具有一个
name
属性,这个属性是一个字符串;
它可以通过构造函数在 web 应用程序中创建,
或者是对底层操作系统文件系统中的一个 字节 序列的引用。
如果 File
对象是对磁盘上文件的
字节 序列的引用,
则其 快照状态
应设置为创建该 File
对象时文件在磁盘上的状态。
注意: 这是一个对于用户代理来说实现起来非常复杂的要求,
因此它不是 必须 而是 应该 [RFC2119]。
用户代理应尽力将 File
对象的
快照状态 设置为创建引用时磁盘上存储的状态。
如果文件在引用创建之后被修改,
则该 File
的 快照状态 将与底层存储的状态不一致。
用户代理可以使用修改时间戳和其他机制来维护 快照状态,
但这留作实现细节。
当一个 File
对象引用磁盘上的文件时,
用户代理必须返回该文件的 type
,
并且必须遵循以下的 文件类型指南:
-
用户代理必须将
type
以小写形式的 ASCII 编码字符串返回, 这样当它被转换为相应的字节序列时, 它是一个 可解析的 MIME 类型, 如果无法确定类型,则返回空字符串 – 0 字节。 -
当文件类型为
text/plain
时,用户代理不得在媒体类型的参数字典部分附加 charset 参数 [MIMESNIFF]。 -
用户代理不得尝试启发式的编码确定方法, 包括统计方法。
[Exposed =(Window ,Worker ),Serializable ]interface :
File Blob {(
constructor sequence <BlobPart >fileBits ,USVString fileName ,optional FilePropertyBag = {});
options readonly attribute DOMString name ;readonly attribute long long lastModified ; };dictionary :
FilePropertyBag BlobPropertyBag {long long lastModified ; };
File
对象是
可序列化对象。它们的 序列化步骤,给定 value 和 serialized 时,步骤如下:
-
将 serialized.[[SnapshotState]] 设置为 value 的 快照状态。
-
将 serialized.[[ByteSequence]] 设置为 value 的底层字节序列。
-
将 serialized.[[Name]] 设置为 value 的
name
属性的值。 -
将 serialized.[[LastModified]] 设置为 value 的
lastModified
属性的值。
它们的 反序列化步骤,给定 value 和 serialized 时,步骤如下:
-
将 value 的 快照状态 设置为 serialized 的 [[SnapshotState]]。
-
将 value 的底层字节序列设置为 serialized 的 [[ByteSequence]]。
-
将 value 的
name
属性初始化为 serialized 的 [[Name]]。 -
将 value 的
lastModified
属性初始化为 serialized 的 [[LastModified]]。
4.1. 构造函数
File
构造函数时,可以传入两个或三个参数,取决于是否使用了可选的字典参数。
当调用 File()
构造函数时,用户代理必须执行以下步骤:
-
根据
fileBits
和options
,获取 处理 blob 部件 的结果,赋值给 bytes。 -
将构造函数的
fileName
参数赋值给 n。注意:不同的底层操作系统文件系统使用不同的文件名约定; 构造文件时,强制使用 UTF-16 可减少文件名转换为 字节 序列时的歧义。
-
通过执行以下子步骤处理
FilePropertyBag
字典参数:-
如果提供了
type
成员且不是空字符串, 则将字典成员type
赋值给 t。 如果 t 包含任何不在 U+0020 到 U+007E 范围内的字符, 则将 t 设为空字符串并从这些子步骤中返回。 -
将 t 中的每个字符转换为 ASCII 小写。
-
如果提供了
lastModified
成员, 则将字典成员lastModified
赋值给 d。 如果未提供, 则将 d 设为当前日期和时间, 以自 Unix Epoch(相当于Date.now()
[ECMA-262])以来的毫秒数表示。注意:由于 ECMA-262 的
Date
对象转换为代表自 Unix Epoch 以来的毫秒数的long long
值, 因此lastModified
成员可以是Date
对象 [ECMA-262]。
-
-
返回一个新的
File
对象 F,使得:-
F 指向 bytes 字节序列。
-
F 的
size
设置为 bytes 的总字节数。 -
F 的
name
设置为 n。 -
F 的
type
设置为 t。 -
F 的
lastModified
设置为 d。
-
4.1.1. 构造函数参数
File()
构造函数可以使用以下参数调用:
fileBits
sequence
-
可以按任意顺序包含以下任意数量的元素:
-
BufferSource
元素。 -
USVString
元素。
-
fileName
参数- 一个
USVString
参数,表示文件的名称; 该构造函数参数的规范条件可在 § 4.1 构造函数 中找到。 - 一个可选的
FilePropertyBag
字典 -
除了 BlobPropertyBag 成员 之外,还接受一个成员:
-
一个可选的
lastModified
成员, 必须是long long
类型; 此成员的规范条件在 § 4.1 构造函数 中提供。
-
4.2. 属性
name
, 类型为 DOMString, 只读- 文件的名称。
获取时,这必须返回文件的名称,作为字符串。
不同的底层操作系统文件系统使用不同的文件名变体和约定;
这只是文件的名称,不包括路径信息。
获取时,如果用户代理无法提供此信息,
则必须返回空字符串。
如果使用构造函数创建了
File
对象, 有关此属性的更多规范条件请参见 § 4.1 构造函数。 lastModified
, 类型为 long long, 只读- 文件的最后修改日期。
获取时,如果用户代理能够提供此信息,
则必须返回一个
long long
,表示文件最后修改时间, 为自 Unix Epoch 以来的毫秒数。 如果最后的修改日期和时间未知, 该属性必须返回当前日期和时间, 以long long
表示自 Unix Epoch 以来的毫秒数; 这相当于Date
[ECMA-262]。 如果使用构造函数创建了. now() File
对象, 有关此属性的更多规范条件请参见 § 4.1 构造函数。
File
接口在暴露 FileList
类型属性的对象上可用;
这些对象在 HTML 中定义 [HTML]。
继承自 Blob
的
File
接口是不可变的,
因此表示可以在启动 读取操作 时读取到内存中的文件数据。
用户代理必须将读取时不再存在的文件处理为 错误,
如果在 Web Worker 上使用 FileReaderSync
则抛出 NotFoundError
异常,
或者触发 error
事件,
error
属性返回 NotFoundError
。
var file= document. getElementById( "filePicker" ). files[ 0 ]; var date= new Date( file. lastModified); println( "您选择的文件是 " + file. name+ ",最后修改日期为 " + date. toDateString() + "。" ); ... // 生成具有特定最后修改日期的文件 var d= new Date( 2013 , 12 , 5 , 16 , 23 , 45 , 600 ); var generatedFile= new File([ "初稿 ...." ], "Draft1.txt" , { type: "text/plain" , lastModified: d}) ...
5. FileList 接口
注意: FileList
接口应被视为“存在风险”,
因为 Web 平台上的普遍趋势是用 Array
对象替代这种接口,正如 ECMAScript 所定义的 [ECMA-262]。
尤其是,类似 filelist
的语法存在风险;
大多数其他 FileList
的程序化使用不太可能受到迁移到 Array
类型的影响。
此接口是一个 File
对象的列表。
[Exposed =(Window ,Worker ),Serializable ]interface {
FileList getter File ?item (unsigned long index );readonly attribute unsigned long length ; };
FileList
对象是 可序列化的对象。其 序列化步骤,
给定 value 和 serialized,如下所示:
其 反序列化步骤,给定 serialized 和 value,如下所示:
<input type="file">
元素,
然后访问选定的文件。
// uploadData 是表单元素 // fileChooser 是类型为 'file' 的输入元素 var file= document. forms[ 'uploadData' ][ 'fileChooser' ]. files[ 0 ]; // 可选语法是 // var file = document.forms['uploadData']['fileChooser'].files.item(0); if ( file) { // 执行文件操作 }
5.1. 属性
length
, 类型为 unsigned long, 只读- 必须返回
FileList
对象中文件的数量。 如果没有文件,此属性必须返回 0。
5.2. 方法和参数
item(index)
-
必须返回 index 位置的
File
对象 在FileList
中。 如果在FileList
中没有 index 位置的File
对象, 那么该方法必须返回null
。index
必须被用户代理 视为表示File
对象在FileList
中位置的值, 其中 0 表示第一个文件。支持的属性索引 是从零到 小于File
对象数量的数字范围。 如果没有这样的File
对象, 那么就没有支持的属性索引。
注意: HTMLInputElement
接口有一个类型为 FileList
的只读属性,
这是上例中访问的内容。
其他具有类型为 FileList
只读属性的接口包括 DataTransfer
接口。
6. 读取数据
6.1. 文件读取任务源
本规范定义了一个新的通用 任务源,称为 文件读取任务源,
用于本规范中排队的所有任务,这些任务用于读取与 Blob
和 File
对象相关的字节序列。
它用于响应异步读取二进制数据的功能。
6.2. FileReader
API
[Exposed =(Window ,Worker )]interface :
FileReader EventTarget {constructor (); // async read methodsundefined readAsArrayBuffer (Blob );
blob undefined readAsBinaryString (Blob );
blob undefined readAsText (Blob ,
blob optional DOMString );
encoding undefined readAsDataURL (Blob );
blob undefined abort (); // statesconst unsigned short = 0;
EMPTY const unsigned short = 1;
LOADING const unsigned short = 2;
DONE readonly attribute unsigned short readyState ; // File or Blob datareadonly attribute (DOMString or ArrayBuffer )?result ;readonly attribute DOMException ?error ; // event handler content attributesattribute EventHandler onloadstart ;attribute EventHandler onprogress ;attribute EventHandler onload ;attribute EventHandler onabort ;attribute EventHandler onerror ;attribute EventHandler onloadend ; };
一个 FileReader
对象有一个关联的 状态,
可以是 "empty"
,"loading"
,或者 "done"
。初始状态为
"empty"
。
一个 FileReader
对象有一个关联的 结果(null
,一个 DOMString
或 ArrayBuffer
)。
初始值为 null
。
一个 FileReader
对象有一个关联的 错误(null
或 DOMException
)。
初始值为 null
。
FileReader()
构造函数在调用时,必须返回一个新的 FileReader
对象。
readyState
属性的 getter 在调用时,基于 this 的 状态,并执行相应的步骤:
result
属性的 getter 在调用时,必须返回 this 的 结果。
error
属性的 getter 在调用时,必须返回 this 的 错误。
FileReader
fr 有一个关联的 读取操作 算法,
该算法在给定 blob,type 和一个可选的 encodingName 的情况下,运行以下步骤:
-
如果 fr 的 状态 为
"loading"
, 抛出一个InvalidStateError
和DOMException
。 -
将 fr 的 状态 设置为
"loading"
。 -
将 fr 的 结果 设置为
null
。 -
将 fr 的 错误 设置为
null
。 -
让 stream 成为调用 获取流 在 blob 上的结果。
-
让 reader 成为 从流中获取 reader 的结果。
-
让 bytes 成为空的 字节序列。
-
让 chunkPromise 成为 从流中读取一个数据块 的结果。
-
让 isFirstChunk 为 true。
-
并行,在此期间一直循环:
-
等待 chunkPromise 被履行或拒绝。
-
如果 chunkPromise 被履行,并且 isFirstChunk 为 true,将一个任务加入队列,以 触发一个进度事件,事件名为
loadstart
,在 fr 上触发。我们 可能会将
loadstart
修改为同步调度, 以对齐 XMLHttpRequest 的行为。[Issue #119] -
将 isFirstChunk 设置为 false。
-
如果 chunkPromise 的履行结果为一个对象,且其
done
属性为 false 并且value
属性为Uint8Array
对象,运行以下步骤: -
否则,如果 chunkPromise 的履行结果是一个
done
属性为 true 的对象,将一个任务加入队列,运行以下步骤并中止该算法: -
否则,如果 chunkPromise 被拒绝并带有错误 error,将一个任务加入队列,运行以下步骤并中止该算法:
-
使用 文件读取任务源 执行所有这些任务。
6.2.1. 事件处理程序内容属性
以下是事件处理程序内容属性(及其对应的事件处理程序事件类型),
用户代理必须在作为 DOM 属性的 FileReader
上支持这些属性:
事件处理程序内容属性 | 事件处理程序事件类型 |
---|---|
onloadstart
| loadstart
|
onprogress
| progress
|
onabort
| abort
|
onerror
| error
|
onload
| load
|
onloadend
| loadend
|
6.2.2. FileReader 状态
FileReader
对象可以处于三种状态之一。
readyState
属性告诉你对象处于哪种状态:
EMPTY
(数值 0)-
FileReader
对象已被构建, 且没有待处理的读取操作。 任何 读取方法 尚未被调用。 这是新创建的FileReader
对象的默认状态, 直到调用了其中一个 读取方法。 LOADING
(数值 1)DONE
(数值 2)-
整个
File
或Blob
已被读取到内存中, 或发生了 文件读取错误, 或读取操作通过abort()
中止。FileReader
不再读取File
或Blob
。 如果readyState
被设置为DONE
, 这意味着至少有一个 读取方法 已在此FileReader
上被调用。
6.2.3. 读取文件或 Blob
FileReader
接口提供了几种 异步读取方法——readAsArrayBuffer()
,
readAsBinaryString()
,
readAsText()
和 readAsDataURL()
,
用于将文件读取到内存中。
注意: 如果在同一个 FileReader
对象上调用了多个并发的读取方法,
用户代理会在 InvalidStateError
中抛出异常,
当 readyState
= LOADING
时。
(FileReaderSync
提供了几种 同步读取方法。
集体来说,FileReader
和 FileReaderSync
的同步和异步读取方法被统称为 读取方法。)
6.2.3.1. readAsDataURL()
方法
readAsDataURL(blob)
方法,
被调用时,必须为 blob 启动一个 DataURL 的读取操作。
6.2.3.2. readAsText()
方法
readAsText(blob, encoding)
方法,
被调用时,必须为 blob 启动一个 Text 和 encoding 的读取操作。
6.2.3.3.
readAsArrayBuffer()
readAsArrayBuffer(blob)
方法,
被调用时,必须为 blob 启动一个 ArrayBuffer 的读取操作。
6.2.3.4.
readAsBinaryString()
方法
readAsBinaryString(blob)
方法,
被调用时,必须为 blob 启动一个 BinaryString 的读取操作。
注意: 推荐使用 readAsArrayBuffer()
而不是 readAsBinaryString()
,
后者仅为了向后
兼容。
6.2.3.5. abort()
方法
当调用 abort()
方法时,
用户代理必须执行以下步骤:
-
如果 this 的 状态 为
"empty"
或 this 的 状态 为"done"
,则将 this 的 result 设置为null
并终止此算法。 -
如果 this 的 状态 为
"loading"
,则将 this 的 状态 设置为"done"
并将 this 的 result 设置为null
。
6.3. 打包数据
Blob
具有一个关联的 打包数据 算法,
给定 bytes,type,一个可选的 mimeType 和一个可选的 encodingName,
根据 type 切换并执行相关步骤:
- DataURL
-
根据以下注意事项,将 bytes 作为 DataURL 返回 [RFC2397]:
-
如果可用,使用 mimeType 作为 Data URL 的一部分, 以符合 Data URL 规范 [RFC2397]。
-
如果 mimeType 不可用,则返回没有媒体类型的 Data URL。[RFC2397]。
需要更好地指定如何生成 DataURL。[Issue #104]
-
- Text
- ArrayBuffer
-
返回一个新的
ArrayBuffer
,其内容为 bytes。 - BinaryString
-
将 bytes 作为一个二进制字符串返回, 其中每个字节由一个值相等的代码单元 [0..255] 表示。
6.4. 事件
FileReader
对象必须是此规范中所有事件的事件目标。
当本规范要求 触发一个名为 e
的进度事件 时(对于某些 ProgressEvent
e
在给定的 FileReader
reader
上),
以下是规范要求:
6.4.1. 事件概述
以下是会在 触发在 FileReader
对象上的事件。
事件名称 | 接口 | 触发时机… |
---|---|---|
loadstart
| ProgressEvent
| 读取开始时。 |
progress
| ProgressEvent
| 正在读取(和解码) blob 时。
|
abort
| ProgressEvent
| 当读取已中止时。
例如,通过调用 abort()
方法。
|
error
| ProgressEvent
| 当读取失败时(请参阅文件读取错误)。 |
load
| ProgressEvent
| 读取成功完成时。 |
loadend
| ProgressEvent
| 请求已完成(无论成功与否)。 |
6.4.2. 事件不变性概述
本节为说明性内容。
以下是不变性,适用于在此规范中的给定异步 读取方法 的 事件触发:
-
一旦
loadstart
事件被触发, 对应的loadend
会在读取完成时触发, 除非下列情况之一为真:注意: 事件
loadstart
和loadend
之间不是一对一的关系。这个例子展示了“读取链”:在事件处理程序中启动另一个读取,而“第一个”读取继续处理。// 如下代码... reader. readAsText( file); reader. onload= function (){ reader. readAsText( alternateFile);} ..... //... loadend 事件不应为第一次读取触发 reader. readAsText( file); reader. abort(); reader. onabort= function (){ reader. readAsText( updatedFile);} //... loadend 事件不应为第一次读取触发 -
当
blob
完全读取到内存中时,将触发一个progress
事件。 -
在
abort
、load
或error
触发后,不会触发progress
事件。 对于给定的读取,最多只触发一次abort
、load
或error
。
6.5. 在线程中读取
Web Workers 允许使用同步的 File
或 Blob
读取 API,
因为在线程上进行的读取不会阻塞主线程。
本节定义了一个可以在 Workers 内使用的同步 API [[Web Workers]]。
Workers 可以同时使用异步 API(FileReader
对象)和同步 API(FileReaderSync
对象)。
6.5.1. FileReaderSync
API
此接口提供了 同步读取 File
或 Blob
对象到内存中的方法。
[Exposed =(DedicatedWorker ,SharedWorker )]interface {
FileReaderSync (); // Synchronously return strings
constructor ArrayBuffer readAsArrayBuffer (Blob );
blob DOMString readAsBinaryString (Blob );
blob DOMString readAsText (Blob ,
blob optional DOMString );
encoding DOMString readAsDataURL (Blob ); };
blob
6.5.1.1. 构造函数
当调用 FileReaderSync()
构造函数时,
用户代理必须返回一个新的 FileReaderSync
对象。
6.5.1.2. readAsText()
readAsText(blob, encoding)
方法被调用时,
必须运行以下步骤:
-
将 stream 设置为调用 get stream 方法获取的 blob 的结果。
-
将 reader 设置为从 stream 中通过 获取 reader 方法得到的结果。
-
将 promise 设置为通过 读取所有字节 从 stream 中 使用 reader 得到的结果。
-
等待 promise 完成或被拒绝。
-
如果 promise 返回的结果为 字节序列 bytes:
-
返回 package data 的结果,输入为 bytes,Text,blob 的
type
,以及 encoding。
-
-
抛出 promise 的拒绝原因。
6.5.1.3.
readAsDataURL()
方法
readAsDataURL(blob)
方法,
被调用时,必须运行以下步骤:
-
将 stream 设置为调用 get stream 方法获取的 blob 的结果。
-
将 reader 设置为从 stream 中通过 获取 reader 方法得到的结果。
-
将 promise 设置为通过 读取所有字节 从 stream 中使用 reader 得到的结果。
-
等待 promise 完成或被拒绝。
-
如果 promise 返回的结果为 字节序列 bytes:
-
返回 package data 的结果,输入为 bytes、DataURL 以及 blob 的
type
。
-
-
抛出 promise 的拒绝原因。
6.5.1.4.
readAsArrayBuffer()
方法
readAsArrayBuffer(blob)
方法,
被调用时,必须运行以下步骤:
-
将 stream 设置为调用 get stream 方法获取的 blob 的结果。
-
将 reader 设置为从 stream 中通过 获取 reader 方法得到的结果。
-
将 promise 设置为通过 读取所有字节 从 stream 中使用 reader 得到的结果。
-
等待 promise 完成或被拒绝。
-
如果 promise 返回的结果为 字节序列 bytes:
-
返回 package data 的结果,输入为 bytes、ArrayBuffer 以及 blob 的
type
。
-
-
抛出 promise 的拒绝原因。
6.5.1.5.
readAsBinaryString()
方法
readAsBinaryString(blob)
方法,
被调用时,必须运行以下步骤:
-
将 stream 设置为调用 get stream 方法获取的 blob 的结果。
-
将 reader 设置为从 stream 中通过 获取 reader 方法得到的结果。
-
将 promise 设置为通过 读取所有字节 从 stream 中使用 reader 得到的结果。
-
等待 promise 完成或被拒绝。
-
如果 promise 返回的结果为 字节序列 bytes:
-
返回 package data 的结果,输入为 bytes、BinaryString 以及 blob 的
type
。
-
-
抛出 promise 的拒绝原因。
注意: 使用 readAsArrayBuffer()
方法优先于 readAsBinaryString()
,
后者是为了向后兼容而提供的。
7. 错误与异常
文件读取错误 可能会在从底层文件系统读取文件时发生。 下面列出的潜在错误情况是参考信息。
-
正在访问的
文件
或Blob
在调用 异步读取方法 或 同步读取方法 时可能不存在。 这可能是由于在获取引用后文件已被移动或删除 (例如,与另一个应用程序并发修改)。 参见NotFoundError
。 -
某个
文件
或Blob
可能不可读。 这可能是由于在获取对文件
或Blob
的引用后发生的权限问题 (例如,与另一个应用程序的并发锁定)。 此外,快照状态 可能已更改。 参见NotReadableError
。 -
用户代理可能会确定某些文件不适合在 Web 应用程序中使用。 文件在原始文件选择后可能会在磁盘上发生更改, 从而导致无效读取。 此外,某些文件和目录结构可能会被底层文件系统视为受限; 尝试从这些文件中读取可能会被视为安全违规。 参见 § 9 安全与隐私考量 以及
SecurityError
。
7.1. 抛出异常或返回错误
本节为规范性内容。
当读取 文件
或 Blob
时,读取操作可能因错误条件而终止;
导致 get stream
算法失败的具体错误条件称为 失败原因。
失败原因 之一包括 NotFound、UnsafeFile、TooManyReads、SnapshotState 或 FileLock。
如果因某个特定 失败原因 出现错误,同步读取方法会 抛出下表中的异常。
异步读取方法使用 error
属性,返回 DOMException
对象(下表中的最合适类型),
如果出现错误是由于某个特定 失败原因,
否则返回 null。
类型 | 描述和失败原因 |
---|---|
NotFoundError
|
如果在处理读取时,文件 或
Blob
资源未找到,
这是 NotFound 失败原因。
对于异步读取方法, |
SecurityError
|
如果:
对于异步读取方法, 这是在任何其他 失败原因 不适用的情况下使用的安全错误。 |
NotReadableError
|
如果:
对于异步读取方法, |
8. 用于 Blob 和 MediaSource 的 URL 参考
本节定义了用于引用 Blob
和 MediaSource
对象的 URL 方案。
8.1. 介绍
本节为说明性内容。
Blob(或对象)URL 是类似于
blob:http://example.com/550e8400-e29b-41d4-a716-446655440000
这样的 URL。
这使得 Blob
和
MediaSource
能够与其他仅设计用于使用 URL 的 API 进行集成,例如
img
元素。Blob URL 也可用于导航或触发本地生成数据的下载。
为此目的,URL
接口公开了两个静态方法,createObjectURL(obj)
和 revokeObjectURL(url)
。
第一个方法创建从 URL 到 Blob
的映射,第二个方法撤销该映射。
只要映射存在,Blob
就不能被垃圾回收,
因此在不再需要引用时,必须注意尽快撤销 URL。
当创建 URL 的全局对象消失时,所有 URL 都会被撤销。
8.2. 模型
每个用户代理都必须维护一个 blob URL 存储。 一个 blob URL 存储 是一个 映射,其中 键 是 有效的 URL 字符串,值 是 blob URL 条目。
一个 blob URL 条目包含一个对象(类型为 Blob
或 MediaSource
)和一个环境(一个环境设置对象)。
注意:规范必须使用获取 blob 对象算法来访问 blob URL 条目的对象。
键 在 blob URL 存储(也称为 blob URL)中是 有效的 URL 字符串,当 解析 后会生成一个 URL,其 方案等于 "blob
",
空主机,以及一个由一个元素组成的 路径,该元素本身也是一个 有效的 URL 字符串。
navigation
"
environment,
执行以下步骤。它们返回一个对象。
-
令 isAuthorized 为 true。
-
如果 environment 不是字符串 "
navigation
",则将 isAuthorized 设置为使用 blobUrlEntry 和 environment 检查同分区 blob URL 使用情况的结果。 -
如果 isAuthorized 为 false,则返回失败。
-
返回 blobUrlEntry 的对象。
-
让 result 为空字符串。
-
将字符串 "
blob:
" 附加到 result。 -
让 settings 为 当前设置对象。
-
让 origin 为 settings 的 来源。
-
让 serialized 为 来源的 ASCII 序列化。
-
如果 serialized 是 "
null
",则将其设置为实现定义的值。 -
将 serialized 附加到 result。
-
将 U+0024 SOLIDUS (
/
) 附加到 result。 -
生成一个 UUID [RFC4122] 作为字符串并将其附加到 result。
-
返回 result。
-
让 store 为用户代理的 blob URL 存储。
-
让 url 为 生成新的 blob URL 的结果。
-
让 entry 为一个新的 blob URL 条目,包含 object 和 当前设置对象。
-
设置 store[url] 为 entry。
-
返回 url。
-
让 store 为用户代理的 blob URL 存储;
-
让 url string 为 序列化 的 url 结果。
-
移除 store[url string]。
8.3. blob URL 的解析模型
-
令 store 为用户代理的blob URL 存储。
-
令 url string 为设置了排除片段标志的序列化 url 的结果。
-
如果 store[url string] 存在,则返回 store[url string];否则返回失败。
对于 blob URL 的解析和获取模型的进一步要求,在 [URL] 和 [Fetch] 规范中定义。
8.3.1. blob URL 的来源
本节为说明性内容。
blob URL 的来源总是与创建该 URL 的环境相同,只要该 URL 尚未被撤销。这是通过 [URL] 规范在解析 URL 时查找 blob URL 存储 中的条目,并使用该条目返回正确的来源来实现的。
如果 URL 被撤销,来源的序列化仍将与创建 blob URL 的环境的来源序列化相同,但对于不透明的来源,来源本身可能是不同的。然而,这种区别是不可观察到的,因为已撤销的 blob URL 无法再被解析或获取。
8.3.2. blob URL 的访问限制
Blob URL 只能从存储密钥与创建 blob URL 的环境的存储密钥匹配的环境中获取。Blob URL 导航不受此限制。
-
令 blobStorageKey 为使用 blobUrlEntry 的环境为非存储目的获取存储密钥的结果。
-
令 environmentStorageKey 为使用 environment 为非存储目的获取存储密钥的结果。
-
如果 blobStorageKey 与 environmentStorageKey 不相等,则返回 false。
-
返回 true。
8.3.3. blob URL 的生命周期
本规范通过以下步骤扩展了 卸载文档清理步骤:
-
让 store 为用户代理的 blob URL 存储。
8.4. 创建和撤销 blob URL
Blob URL 是通过 URL
对象暴露的静态方法创建和撤销的。
撤销一个 blob URL 会将 blob URL 与其引用的资源解耦,如果在撤销后对其进行解引用,
用户代理必须像发生了 网络错误 一样处理。
本节描述了 URL 规范的补充接口 [URL] 并介绍了blob URL 的创建和撤销方法。
[Exposed =(Window ,DedicatedWorker ,SharedWorker )]partial interface URL {static DOMString createObjectURL ((Blob or MediaSource ));
obj static undefined revokeObjectURL (DOMString ); };
url
createObjectURL(obj)
静态方法必须返回为 obj 添加条目到 blob URL
存储的结果。
revokeObjectURL(url)
静态方法必须执行以下步骤:
-
令 urlRecord 为解析 url 的结果。
-
如果 urlRecord 的方案不是“
blob
”,则返回。 -
令 entry 为 urlRecord 的blob URL 条目。
-
如果 entry 为 null,则返回。
-
令 isAuthorized 为使用 entry 和当前设置对象检查同分区 blob URL 使用情况的结果。
-
如果 isAuthorized 为 false,则返回。
-
从 Blob URL 存储中移除 url 的条目。
注意:这意味着尝试撤销未注册的 URL 或从不同存储分区的环境中注册的 URL 将会静默失败,而不是抛出某种错误。 如果发生这种情况,用户代理可能会在错误控制台中显示一条消息。
注意:在撤销 url 后尝试解引用它将导致 网络错误。 在撤销 url 之前启动的请求仍应成功。
window1
和 window2
是独立的,
但在 同源;window2
可能是
iframe
在 window1
内。
myurl= window1. URL. createObjectURL( myblob); window2. URL. revokeObjectURL( myurl);
由于用户代理具有一个全局的 blob URL 存储,
因此可以从与创建它不同的窗口撤销一个对象 URL。
URL.
调用
确保后续对 revokeObjectURL()
myurl
的解引用会导致用户代理像发生了 网络错误 一样处理。
8.4.1. Blob URL 创建和撤销的示例
Blob URL 是用于获取 Blob
对象的字符串,并且只要最初使用
URL.
创建它们的 createObjectURL()
document
存在,它们就可以一直存在——请参阅§ 8.3.3 blob URL
的生命周期。
本节通过解释给出了创建和撤销 blob URL 的示例用法。
img
元素 [HTML] 引用了相同的
blob URL:
url= URL. createObjectURL( blob); img1. src= url; img2. src= url;
URL.revokeObjectURL()
:
var blobURLref= URL. createObjectURL( file); img1= new Image(); img2= new Image(); // 两个赋值操作均正常工作 img1. src= blobURLref; img2. src= blobURLref; // ... 页面加载后 // 检查两个图像是否已加载完成 if ( img1. complete&& img2. complete) { // 确保后续的引用抛出异常 URL. revokeObjectURL( blobURLref); } else { msg( "无法预览图像!" ); // 撤销基于字符串的引用 URL. revokeObjectURL( blobURLref); }
上面的示例允许多次引用单个blob URL,
然后在两个图像对象都加载完毕后,Web 开发者撤销该blob
URL字符串。
虽然不限制blob URL的使用次数提供了更大的灵活性,
但它增加了泄漏的可能性;
开发者应将其与相应的
URL.
调用配对使用。
revokeObjectURL()
9. 安全和隐私考虑
本节是说明性的。
本规范允许 Web 内容读取来自底层文件系统的文件,并提供通过唯一标识符访问文件的方式,因此涉及一些安全考虑。 本规范还假设主要的用户交互是通过 HTML 表单中的
<input type="file">
元素 [HTML], 并且 FileReader
对象读取的所有文件均已由用户选择。 重要的安全考虑包括防止恶意的文件选择攻击(选择循环), 防止访问系统敏感文件,并防止文件在选择后被修改。
- 防止选择循环
-
在文件选择过程中,用户可能会被与
<input type="file">
相关联的文件选择器轰炸(陷入“必须选择”循环中,强制选择才能关闭文件选择器),用户代理可以通过使返回的FileList
对象的大小为 0 来阻止对任何选定文件的访问。 - 系统敏感文件
-
(例如 /usr/bin 中的文件、密码文件和其他原生操作系统可执行文件)通常不应暴露给 Web 内容,并且不应通过 blob URL 进行访问。用户代理可以为同步读取方法抛出
SecurityError
异常,或为异步读取返回SecurityError
异常。
10. 需求和用例
本节讨论此 API 的需求,并说明一些用例。 此版本的 API 并未满足所有用例; 后续版本可能会解决这些问题。
-
一旦用户授予权限,用户代理应提供通过编程方式直接从本地文件读取和解析数据的能力。
-
数据应该能够存储在本地,以便以后使用,这对于 Web 应用程序的离线数据访问非常有用。
-
用户代理应提供通过编程方式根据数据量和文件名保存本地文件的能力。
注意:虽然本规范未提供触发下载的显式 API 调用,但 HTML5 规范已解决此问题。
download
属性的a
元素会启动下载,保存具有指定名称的File
。 此 API 和download
属性的结合 使 Web 应用程序能够创建文件并将其保存到本地。 -
用户代理应提供一种简化的编程方式,将文件中的数据发送到远程服务器,其效率应高于当前基于表单的上传方式。
-
用户代理应提供暴露给脚本的 API,公开上述功能。 每当与文件系统进行交互时,UI 会通知用户,并且用户可以完全取消或中止事务。 用户会被通知任何文件选择,并可以取消这些选择。 无需用户干预,无法静默调用这些 API。
致谢
本规范最初由 SVG 工作组开发。特别感谢 Mark Baker 和 Anne van Kesteren 提供的反馈意见。
感谢 Robin Berjon、Jonas Sicking 和 Vsevolod Shmyroff 编辑了最初的规范。
特别感谢 Olli Pettay、Nikunj Mehta、Garrett Smith、Aaron Boodman、Michael Nordman、Jian Li、Dmitry Titov、Ian Hickson、Darin Fisher、Sam Weinig、Adrian Bateman 和 Julian Reschke。
感谢 W3C WebApps 工作组,和 public-webapps@w3.org 邮件列表上的参与者。