FileReader API

无需后端服务器,异步读取和解释上传的文件。
网站是如何在不存储任何数据的情况下解释上传的文件的吗?FileReader API就是答案!它允许客户端应用程序异步读取和解释上传的文件。

要在您自己的客户端应用程序中执行此操作,您还需要了解File APIBlob API。这些是您将使用FileReader API读取的对象。您还可以使用FileReader API来分析从拖放操作中获取的文件。

注意:这与较新的File System API不同,后者提供了浏览器(和客户端JavaScript)访问本地文件系统的功能。

尽管这个API已经存在一段时间了(Chrome在版本6中开始支持它),但现代用法的部分支持时间并不长,例如File API(在Chrome 13中发布)和File()构造函数(在Chrome 38中发布)。

基础知识

FileReader API在基本用法中,可以与<input type="file" />结合使用。一旦通过文件浏览器选择了文件,或者将文件拖放到文件字段上,就会在输入元素上创建一个新的File对象。

FileReader可以与任何File对象一起使用,但我们将探讨一个基本的用法场景。

让我们尝试将File对象传递给FileReader API,如下所示:

1
2
3
4
function readFile(file) {
const fileReader = new FileReader();
fileReader.readAsText(file);
}

然而,上面的示例还不够完整。FileReader API默认是异步的,并且不使用Promises。相反,您可以监听几个事件。

现在,让我们专注于以下事件:

  • load:在成功加载文件时触发
  • error:在读取文件失败时触发
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function readFile() {
    const fileReader = new FileReader();
    const resultContainer = document.getElementById('result');
    const file = document.getElementById('uploaded-file').files[0];

    if (file) {
    fileReader.readAsText(file);
    }

    fileReader.addEventListener('load', () => {
    resultContainer.innerText = fileReader.result
    }, { once: true });
    }
    请注意,在上面的示例中,我们将resultContainer的文本设置为FileReader触发load事件后所获得的结果。

fileReader对象上的result属性正是您所期望的:FileReader从文件中读取的内容包含在result属性中。

虽然它无法读取每种类型文件的内容,但FileReader提供了以下方法:

  • readAsText()
  • readAsDataURL()
  • readAsArrayBuffer()

方法:readAsText()

首先是FileReader API提供的非常基础的文本方法。您应该只在较小的文件上使用此方法,因为它会将整个文件读入内存。对于较大的文件,您应该使用readAsArrayBuffer(),因为它返回一个Promise,并且对于较大的文件更加可预测。

在上面的示例中,我们将传递给readFile()的文件并记录readAsText方法的结果。如果我们想读取任何类型的基于文本的文件,例如 .txt.csv 等,这将非常有用。

1
2
3
4
5
6
7
8
9
<label>
Upload file
<input type="file" id="testfile" accept=".txt" onchange="readFile()">
</label>
<br> <br>
<div>
Contents of Text File:
<div id="result"></div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function readFile() {
const fileReader = new FileReader();
const resultContainer = document.getElementById("result");
const file = document.querySelector("input[type=file]").files[0];

if (file) {
fileReader.readAsText(file); // Read the file so fileReader.result is populated.
}

fileReader.addEventListener(
"load",
() => {
resultContainer.textContent = fileReader.result;
},
{ once: true }
);
}

方法:readAsDataURL()

此方法可用于读取图像,类似于如果它们是数据URL字符串时与图像进行交互的方式。这正是此方法的作用:将图像作为base64编码的数据URL返回。

注意:它是readAsDataURL - URL中所有字母都大写 - 而不是readAsDataUrl。使用后者会导致错误 - 它是区分大小写的。

让我们看下面的示例:

1
2
3
4
5
6
<!-- 不要忘记以语义化方式编写HTML! -->
<label>
<input type="file" id="uploaded-file" onchange="readImage()" name="uploaded-file" accept="image/*">
上传一张图片。
</label>
<div id="result"></div>

请注意,我使用accept属性将上传的文件限制为图像类型的MIME类型。查阅MDN上有关如何指定要接受的文件类型的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function readImage() {
const fileReader = new FileReader();
const file = document.getElementById("uploaded-file").files[0];

if (file) {
fileReader.readAsDataUrl(file);
}

fileReader.addEventListener('load', () => {
const result = fileReader.result;
const resultContainer = document.getElementById("result");
const img = document.createElement("img");
img.src = result;
resultContainer.append(img);
}, { once: true })
}

在上面的示例中,我们:

  • 创建一个FileReader
  • 然后监听load事件的发生(意味着文件读取会话成功)
  • 然后创建一个<img>元素,并将图像作为数据URL放入src属性中
  • 最后,将创建的img添加到我们为图像创建的<div>容器中
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <label>
    Upload file
    <input type="file" id="testfile" accept="image/*" onchange="readImage()">
    </label>
    <br> <br>
    <div>
    Image that was uploaded:
    <div id="result"></div>
    </div>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function readImage() {
    const fileReader = new FileReader();
    const file = document.querySelector("input[type=file]").files[0];

    if (file) {
    fileReader.readAsDataURL(file);
    }

    fileReader.addEventListener(
    "load",
    () => {
    const result = fileReader.result;
    const resultContainer = document.getElementById("result");
    const img = document.createElement("img");
    img.src = result;
    resultContainer.append(img);
    },
    { once: true }
    );
    }
    此API非常适用于简单的浏览器操作,甚至可以用于上传图像/文本/文件到后端服务器时的实时状态更新。要在主要社交网络上更新个人资料图片?您可以使用FileReader API来复制此操作。

FileReader事件

FileReader上还有几个其他事件值得了解。

  • abort - 文件读取已被中止(取消)
  • progress - 在读取期间定期触发
  • loadstart / loadend - 可用于在文件加载开始或结束时触发某些操作

这些事件是从ProgressEvent接口扩展的。通过监听FileReader上的progress事件,您可以通过将ProgressEvent上的loaded除以total属性来计算文件读取进度。

1
2
3
4
fileReader.addEventListener("progress", (event) => {
const progress = (event.loaded / event.total) * 100;
console.log(`读取进度:${progress}%`);
});

进阶

FileReader是一个很棒的API,可用于许多客户端应用程序。它是许多您可能已经使用的应用程序的基础。