Skip to content

文件相关

JavaScript 在处理文件、二进制数据和数据转换时,提供了一系列的 API 和对象,比如 File、Blob、FileReader、ArrayBuffer、Base64、Object URL 和 DataURL。每个概念在不同场景中都有重要作用。下面的内容我们将会详细学习每个概念及其在实际应用中的用法。

1.MIME类型

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。

MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。

浏览器通常使用 MIME 类型(而不是文件扩展名)来确定如何处理URL,因此 We b服务器在响应头中添加正确的 MIME 类型非常重要。如果配置不正确,浏览器可能会无法解析文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。

1.1 语法

MIME由类型与子类型两个字符串中间用/分隔而组成,不允许有空格

type/subtype
  • type:表示可以被分多个子类的独立类别
  • subtype:表示细分后的每个类型。

MIME类型对大小写不敏感,但是传统写法都是小写。

两种主要的 MIME 类型在默认类型中扮演了重要的角色:

  • text/plain 表示文本文件的默认值。
  • application/octet-stream 表示所有其他情况的默认值

1.2 常见MIME类型

  • 超文本标记语言文本 .htmltext/html
  • 普通文本 .txttext/plain
  • RTF 文本 .rtfapplication/rtf
  • GIF 图形 .gifimage/gif
  • JPEG 图形 .jpeg、.jpgimage/jpeg
  • au 声音文件 .auaudio/basic
  • MIDI 音乐文件 mid、.midiaudio/midi、audio/x-midi
  • RealAudio 音乐文件 .ra、.ramaudio/x-pn-realaudio
  • MPEG 文件 .mpg、.mpegvideo/mpeg
  • AVI 文件 .avivideo/x-msvideo
  • GZIP 文件 .gzapplication/x-gzip
  • TAR 文件 .tarapplication/x-tar
类型描述典型示例
text表明文件是普通文本,理论上是人类可读text/plain, text/html, text/css, text/javascript
image表明是某种图像。不包括视频,但是动态图(比如动态gif)也使用image类型image/gif, image/png, image/jpeg, image/bmp, image/webp, image/x-icon, image/vnd.microsoft.icon
audio表明是某种音频文件audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav
video表明是某种视频文件video/webm, video/ogg
application表明是某种二进制数据application/octet-stream, application/pkcs12, application/vnd.mspowerpoint, application/xhtml+xml, application/xml, application/pdf

具体可查看MIME类型

2.Blob对象

2.1 概念

在 JavaScript 中,Blob(Binary Large Object)对象用于表示不可变的、原始的二进制数据

可以存储任何类型的数据,比如文件、图片、音频、视频、甚至是纯文本

Blob 提供了一种高效的方式来操作数据文件,而不需要将数据全部加载到内存中,这在处理大型文件或二进制数据时非常有用。

2.2 构造函数

Blob是一个对象,使用需要使用new关键字调用Blob()构造函数创建实例

js
const blob = new Blob([blobParts][, options]);
  • blobParts: 可选,一个可迭代对象
    • 比如 Array,包含 ArrayBufferTypedArrayDataViewBlob、字符串或者任意这些元素的混合
    • 这些元素将会被放入 Blob中。字符串应该是格式良好的 Unicode
  • options: 一个可选的对象,可以设置 type(MIME 类型)和 endings(用于表示换行符)。
    • type:可选,将会被存储到 blob 中的数据的MIME类型。默认值是空字符("")。
    • endings:如果数据是文本,那么如何解释其中的换行符(\n)。默认值 transparent 会将换行符复制到 blob 中而不会改变它们。要将换行符转换为主机系统的本地约定,请指定值 native

简单使用:

js
const blob =new Blob(['hello world'], {type: 'text/plain'});
console.log(blob)

image-20241008100935449

2.3 实例属性

size

只读, Blob 对象中所包含数据的大小(字节)。

js
const blob =new Blob(['阿珍爱上了阿强,在一个有星星的夜晚'], {type: 'text/plain'});
console.log(blob.size)  // 51

type

只读,一个字符串,表明该 Blob 对象所包含数据的 MIME 类型。如果类型未知,则该值为空字符串。

js
const blob =new Blob(['阿珍爱上了阿强,在一个有星星的夜晚'], {type: 'text/plain'});
console.log(blob.type)  // text/plain

2.4 实例方法

text()

该方法将 Blob 的内容读取 UTF-8 格式的字符串。它返回一个 Promise,解析为文本数据

js
const blob = new Blob(['阿珍爱上了阿强,在一个有星星的夜晚'], { type: 'text/plain' })
blob.text().then(text => console.log(text))  // 阿珍爱上了阿强,在一个有星星的夜晚

slice()

可在一个Blob中截取数据,并返回一个新的Blob

js
slice()
slice(start)
slice(start, end)
slice(start, end, contentType)

参数

  • start:需要截取内容的开始字节索引
    • 默认值是 0
    • 若传入的是一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。例如,-10 将会是 Blob的倒数第十个字节
    • 如果你传入的 start 的长度大于源Blob的长度,那么返回的将会是一个长度为 0 并且不包含任何数据的一个 Blob对象。
  • end:需要截取内容的结束字节索引,不包含此索引的数据
    • 默认值就是它的原始长度 size
    • 如果你传入了一个负数,那么这个偏移量将会从数据的末尾从后到前开始计算。举例来说,-10 将会是 Blob的倒数第十个字节。
  • contentType:给新的 Blob赋予一个新的MIME内容类型。这将会把它的 type 属性设为被传入的值。它的默认值是一个空字符串。

返回值:一个新的Blob对象,它包含了调用该方法的原始 blob 对象所包含数据的指定子集。原始的 blob 不会被改变。

js
const blob = new Blob(['阿珍爱上了阿强,在一个有星星的夜晚'], { type: 'text/plain' })

const blob1 = blob.slice()
blob1.text().then(res => console.log(res)) //阿珍爱上了阿强,在一个有星星的夜晚

const blob2 = blob.slice(6)
blob2.text().then(res => console.log(res)) //爱上了阿强,在一个有星星的夜晚

const blob3 = blob.slice(6, 12)
blob3.text().then(res => console.log(res)) //爱上

const blob4 = blob.slice(6, 12, 'utf-8')
blob4.text().then(res => console.log(res)) //爱上

TIP

使用slice()截取汉字时,一个汉字需要3个字节,这是由于 UTF-8 是一种变长编码方式,不同的字符根据其Unicode值的范围采用不同的字节数:

  • 1 个字节:用于ASCII字符(例如英文字母、数字等)
  • 2 个字节:用于一些常用的拉丁字符和其他字符
  • 3 个字节:用于大多数汉字及其他常用符号
  • 4 个字节:用于一些较为冷门的字符

因此,在使用 Blob 对象等处理汉字字符串时,通常会发现每个汉字占用 3 个字节的情况。这个设计使得UTF-8能够向后兼容ASCII,同时有效地支持多种语言和符号。

arrayBuffer()

该方法将 Blob 的内容读取为 ArrayBuffer 对象,适合处理二进制数据。它返回一个 Promise,解析为 ArrayBuffer 数据。

js
const blob = new Blob(["阿珍爱上了阿强,在一个有星星的夜晚"], { type: "text/plain" });

blob.arrayBuffer().then((buffer) => {
  console.log(buffer);
});

image-20241008104034657

stream()

该方法将 Blob 的数据作为一个 ReadableStream 返回,允许你以流的方式处理数据,适合处理大文件。

js
const blob = new Blob(["阿珍爱上了阿强,在一个有星星的夜晚"], { type: "text/plain" });
const stream = blob.stream();
console.log(stream);

image-20241008104455165

2.5 Blob使用场景

Blob 对象在很多场景中非常有用,尤其是在 Web 应用中处理文件、图片或视频等二进制数据时。以下是一些常见的使用场景:

生成文件下载

可以通过 Blob 创建文件并生成下载链接供用户下载文件。

html
<body>
    <button>Download</button>
    <script>
        const downLoad = () => {
            const blob = new Blob(['This is a test file.'], { type: 'text/plain' })
            const url = URL.createObjectURL(blob) // 创建一个 Blob URL
            const a = document.createElement('a')
            a.href = url
            a.download = 'test.txt'
            a.click()
            URL.revokeObjectURL(url) // 释放 URL 对象
        }
        document.querySelector('button').addEventListener('click', downLoad)
    </script>
</body>

上传文件

可以通过 FormData 对象将 Blob 作为文件上传到服务器:

js
const formData = new FormData();
formData.append("file", blob, "example.txt");

fetch("/upload", {
  method: "POST",
  body: formData,
}).then((response) => {
  console.log("File uploaded successfully");
});

读取文件

通过 FileReader API 可以将 Blob 对象读取为不同的数据格式。举例来说,你可以将 Blob 读取为图片并显示在页面上:

html
<body>
    <input type="file" id="fileInput" accept="image/*" />

    <img src="" alt="" id="imageContainer">
    <script>
        const fileInput = document.getElementById("fileInput");

        const imageContainer = document.getElementById("imageContainer");

        fileInput.addEventListener("change", function (event) {
            const file = event.target.files[0];

            if (file && file.type.startsWith("image/")) {
                const reader = new FileReader();

                reader.onload = function (e) {
                    const img = document.querySelector("#imageContainer");
                    img.src = e.target.result;
                };

                reader.readAsDataURL(file);
            } else {
                alert("请选择一个有效的图片文件。");
            }
        });
    </script>
</body>

3.File对象

File 是 JavaScript 中代表文件的数据结构,它继承自 Blob 对象,包含文件的元数据(如文件名、文件大小、类型等)。

File继承Blob对象

image-20241008112404130

3.1 创建File对象

File 对象通常由用户通过 <input type="file"> 选择文件时创建

event.target.files是一个FileList对象,也是个数组,上传的文件在数组第一个元素这中

html
<body>
    <input type="file" id="fileInput" />

    <script>
        const fileInput = document.getElementById("fileInput");

        fileInput.addEventListener("change", function (event) {
            const file = event.target.files[0];
            console.log("文件名:", file.name);
            console.log("文件类型:", file.type);
            console.log("文件大小:", file.size);
        });
    </script>
</body>

<input/>具有multiple属性时,可以多选文件,此时event.target.files中会包含每个文件的数据

html
<body>
    <input type="file" id="fileInput" multiple/>

    <script>
        const fileInput = document.getElementById("fileInput");

        fileInput.addEventListener("change", function (event) {
            const file = event.target.files;
            console.log(file)
        });
    </script>
</body>

也可以使用 JavaScript 构造函数手动创建。

以下是File构造函数,用于创建File对象

3.2 构造函数

js
new File(fileBits, fileName)
new File(fileBits, fileName[, options])

参数

  • fileBits:一个可迭代对象,例如一个ArrayBuffer、TypedArray、DataView、Blob、具有字符串或任何此类元素的组合的数组,将被放入 File 内。请注意,这里的字符串被编码为 UTF-8,与通常的 JavaScript UTF-16 字符串不同。
  • fileName:表示文件名或文件路径的字符串。
  • options:可选,包含文件可选属性的选项对象。可用选项如下:
    • type:可选,表示将放入文件的内容的 MIME 类型的字符串。默认值为 ""
    • endings:可选,如果数据是文本,如何解释内容中的换行符(\n)。默认值 transparent 将换行符复制到 blob 中而不更改它们。要将换行符转换为主机系统的本机约定,指定值为 native
    • lastModified:可选,一个数字,表示 Unix 时间纪元与文件上次修改时间之间的毫秒数。默认值为调用 Date.now()返回的值。
js
const file = new File(["Hello, world!"], "hello-world.txt", {
  type: "text/plain",
});

console.log(file);

image-20241008112518191

blob转file

js
const blob = new Blob(['hello world'], { type: 'text/plain' })
const file = new File([blob], 'test.txt')
const url = URL.createObjectURL(blob)
window.open(url)

3.3 实例属性

因为File继承自Blob,所以包含sizetype属性

lastModified

只读属性,提供文件的上次修改日期,作为自 Unix 纪元(1970 年 1 月 1 日午夜)以来的毫秒数。没有已知最后修改日期的文件返回当前日期。

lastModifiedDate

只读属性,返回文件的最后修改日期。没有已知最后修改日期的文件则返回当前日期。

name

只读属性返回由 File 对象表示的文件的名称。由于安全原因,该属性并不包含文件路径。

webkitRelativePath

只读属性,它规定了文件的路径,相对于用户在 <input> 元素中选择的目录

3.4 实例方法

File本身没有方法,但继承了 Blob 对象的方法,因此可以使用一些 Blob 对象的方法来处理文件数据。

text():读取文件内容,并将其作为文本返回(这是 Blob 的方法,但可以用于 File 对象)。

js
const file = new File(['阿珍爱上了阿强,在一个有星星的夜晚'], 'hello-world.txt', {
    type: 'text/plain',
})

file.text().then(res=>console.log(res))   // 阿珍爱上了阿强,在一个有星星的夜晚

slice():从文件中获取一个子部分数据,返回一个新的 Blob 对象。

js
const file = new File(['阿珍爱上了阿强,在一个有星星的夜晚'], 'hello-world.txt', {
    type: 'text/plain',
})

file.slice(0, 12).text().then(res=>console.log(res))   // 阿珍爱上

arrayBuffer():将文件内容读取为 ArrayBuffer(用于处理二进制数据)。

js
const file = new File(['阿珍爱上了阿强,在一个有星星的夜晚'], 'hello-world.txt', {
    type: 'text/plain',
})

file.arrayBuffer().then((buffer) => {
  console.log(buffer); // 输出文件的 ArrayBuffer
});

image-20241008140829895

stream():返回一个 ReadableStream 对象,可以通过流式读取文件内容。

js
const stream = file.stream();

4.FileList

FileList 接口表示由 HTML的<input/>元素的files属性返回的该类型的对象,

这使你可以访问使用 <input type="file"> 元素选择的文件列表。它还用于使用拖放 API 中放入 Web 内容中的文件列表;

html
<body>
    <input type="file" id="fileInput" accept="image/*" />

    <script>
        const input = document.getElementById('fileInput')
        input.addEventListener('change', event => {
            const files = event.target.files
            console.log(files)
        })
    </script>
</body>

image-20241008142228725

<input/>元素添加mutiple属性,可以多选属性

html
<body>
    <input type="file" id="fileInput" accept="image/*" multiple />

    <script>
        const input = document.getElementById('fileInput')
        input.addEventListener('change', event => {
            const files = event.target.files
            console.log(files)
        })
    </script>
</body>

image-20241008142402339

5.FileReader对象

FileReader 允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数。

在这里插入图片描述

5.1 构造函数

js
const fileReader=new FileReader()

5.2 实例属性

error

返回读取文件时的错误信息

readyState

提供 FileReader 读取操作时的当前状态。

  • 0:还没有加载任何数据,对应静态属性FileReader.EMPTY
  • 1:数据正在被加载,对应静态属性FileReader.LOADING
  • 2:已完成全部的读取请求,对应静态属性FileReader.DONE

result

返回文件的内容。只有在读取操作完成后,此属性才有效

值为一个字符串或者一个ArrayBuffer取决于使用哪种读取方法

读取方法为以下的readAsArrayBuffer、readAsDataURL、readAsText

5.3 实例方法

abort()

中止FileReader的读取操作,触发之后 readyState 为已完成(DONE)

readAsArrayBuffer()

用于开始读取指定 BlobFile的内容。当读取操作完成时,readyState属性变为 DONE,并触发 loadend事件。此时,result属性包含一个表示文件数据的 ArrayBuffer

js
readAsArrayBuffer(blob)

参数:

  • blob:从中读取的 BlobFile对象。

readAsDataURL()

用于开始读取指定 BlobFile的内容。当读取操作完成时,readyState属性变为 DONE,并触发 loadend事件。此时,result属性包含作为 data: URL 的数据,将文件的数据表示为 base64 编码字符串。

js
readAsDataURL(blob)

参数:

  • blob:从中读取的 BlobFile对象。

readAsText()

用于开始读取指定 BlobFile的内容。当读取操作完成时,readyState属性变为 DONE,并触发 loadend事件。并且 result属性包含表示文件内容的文本字符串。

js
readAsText(blob)
readAsText(blob, encoding)

参数:

  • blob:从中读取的 BlobFile对象。
  • encoding:指定用于返回数据的编码的字符串。如果未指定此参数,则默认情况下假定为 UTF-8。

5.4 事件

事件类型

以下事件的事件对象都为ProgressEvent,继承自Event

除了继承自Event的属性,还有如下几个属性

属性描述
ProgressEvent.lengthComputable只读,一个布尔标志,指示底层进程要完成的总工作量以及已完成的工作量是否可计算。换句话说,它表明进展是否可衡量。
ProgressEvent.loaded只读,一个 64 位无符号整数值,指示底层进程已执行的工作量。完成工作的比率可以通过将 total 除以该属性的值来计算。使用 HTTP 下载资源时,仅计算 HTTP 消息的正文,不包括标头和其他开销。
ProgressEvent.total只读,一个 64 位无符号整数,表示底层进程正在执行的工作总量。使用 HTTP 下载资源时,这是 Content-Length(消息正文的大小),不包括标头和其他开销。

abort

abort 事件在读取被中止时触发:例如因为程序调用了FileReader.abort()方法。

此事件不可取消且不会冒泡。

js
const fileReader=new FileReader()

fileReader.addEventListener("abort", (event) => {});

fileReader.onabort = (event) => {};

error

error 事件在由于错误(例如,因为文件未找到或不可读)导致读取失败时触发。

此事件不可取消且不会冒泡。

js
const fileReader=new FileReader()

fileReader.addEventListener("error", (event) => {});

fileReader.onerror = (event) => {};

load

load 事件在成功读取文件时触发

js
const fileReader=new FileReader()

fileReader.addEventListener("load", (event) => {});

fileReader.onload = (load) => {};

一般在此事件中处理读取的数据

html
<body>
    <input type="file" id="fileInput" accept="image/*" multiple />
    <img src="" alt="" >
    <script>
        const input = document.getElementById('fileInput')
        input.addEventListener('change', event => {
            const file = event.target.files[0]
            const reader = new FileReader()
            reader.onload = e => {
                const img = document.querySelector('img')
                img.src = e.target.result
            }

            reader.readAsDataURL(file)
        })
    </script>
</body>

loadend

loadend 事件在文件读取完成无论成功与否)时触发。

此事件不可取消且不会冒泡。

js
const fileReader=new FileReader()

fileReader.addEventListener("loadend", (event) => {});

fileReader.onloadend = () => {};

loadstart

loadstart 事件在文件读取操作开始时触发。

js
const fileReader=new FileReader()

fileReader.addEventListener("loadstart", (event) => {});

fileReader.onloadstart = (event) => {};

progress

progress 事件在 FileReader 读取数据时定期触发。

此事件不可取消且不会冒泡。

js
const fileReader=new FileReader()

fileReader.addEventListener("progress", (event) => {});

fileReader.onprogress = (event) => {};

此事件可以实现读取进度展示

js
input.addEventListener('change', event => {
    const file = event.target.files[0]
    const reader = new FileReader()
    reader.onprogress = event => {
        const progress = (event.loaded / event.total) * 100
        console.log(progress)
    }

    reader.readAsDataURL(file)
})

6.URL相关

createObjectURL()

createObjectURL() 可以给指定的BlobFile对象创建一个url,从而可以在网页上展示,或者文件的下载

js
URL.createObjectURL(object)

参数:

  • object:用于创建 URLFileBlobMediaSource 对象。

新窗口预览图片

html
<body>
    <input type="file" id="fileInput" accept="image/*" />

    <script>
        const fileInput = document.getElementById('fileInput');
        fileInput.addEventListener('change', (event) => {
            const file = event.target.files[0];
            const url=URL.createObjectURL(file);
            open(url);
        })
    </script>
</body>

TIP

每次调用 createObjectURL() 时,都会创建一个新的对象 URL,即使已经为同一个对象创建了一个 URL。当不再需要这些对象时,必须通过调用 URL.revokeObjectURL()来释放它们。

revokeObjectURL()

你完成对对象 URL 的使用后,请调用此方法,让浏览器知道无需再保持对文件的引用。

js
const blob = new Blob(['hello world'], { type: 'text/plain' })
const url = URL.createObjectURL(blob)

URL.revokeObjectURL(url)

MIT Licensed