文件下载,过去一般由后端程序在服务器端生成文件,然后前端通过打开链接的方式从服务器端下载数据,而需要下载的文件在服务器上会有一个临时文件或者永久存在的文件。随着浏览器的发展和高级浏览器的普及,文件下载可以通过接口获取相应的文件流,然后在前端生成相应的下载文件和链接地址,这种方式一般在服务器端没有临时文件或者永久文件,而是将文件数据流存储在数据库中。
本文将介绍通过原生 JavaScript 生成文件和下载文件的方式。
生成文件
对于使用文件,浏览器中有高级对象 File API ,现在已经得到浏览器厂商的广泛支持。使用它创建一个文件非常的简单, File 接口基于 Blob,继承 Blob 功能并对其进行扩展以支持用户系统上的文件。如下:
const file = new File(["DevPoint,开发技术点"], "info.md", { type: "text/plain", });
具体参数描述如下:
数据数组
:第一个参数,它可以是Blob
、ArrayBuffer
,或者字符串。文件名
:第二个参数为文件名称,包括文件后缀。文件配置
:这是一个可选参数,传递文件的实际类型。
为了生成一个文件,包含 text/plain
类型(文本、HTML、CSV 等)数据的文件,生成更抽象的文件类型需要使用 blob
或缓冲区。
CSV或者EXCEL:
const file = new File([filedata], "info.xlsx", { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", });
Blob
ArrayBuffer
是 ECMA 标准的一部分,也可以说是 JavaScript 的一部分。在浏览器中生成文件,除了上面介绍的高级对象 File API 中进行了描述,还有 Blob。
Blob(Binary Large Object)表示二进制类型的大对象。在数据库管理系统中,将二进制数据存储为一个单一个体的集合。Blob 通常是影像、声音或多媒体文件。在 JavaScript 中 Blob 类型的对象表示不可变的类似文件对象的原始数据。
Blob 由一个可选的字符串类型(通常是 MIME 类型)和 blobParts
组成:其他 Blob 对象、字符串和 BufferSource
的序列。
构造函数语法是:
new Blob(blobParts, options);
blobParts
:是Blob/BufferSource/String
值的数组options
:可选对象
type
:Blob 类型,通常是 MIME 类型,例如text/plain
endings
:默认值为transparent
,用于指定包含行结束符\n
的字符串如何被写入。 它是以下两个值中的一个:native
,代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者transparent
,代表会保持blob
中保存的结束符不变。
下载文件
要检查创建文件是否有效,需要访问它,并进行下载。
实现的方式是生成一个包含对文件引用的链接。然后,让 JavaScript 出发时间 click
来点击链接,这样文件就可以下载了。
为了接收文件 URL,需要使用 URL.createObjectURL()
方法将接收文件对象作为参数。然后,通过设置链接的下载属性,指定保存的文件默认名称。
最后,在 DOM 中挂载链接,单击它后,将其从 DOM 中删除。以下是完整的代码:
const file = new File(["DevPoint,开发技术点"], "info.md", { type: "text/plain", }); function download(downfile) { const tmpLink = document.createElement("a"); const objectUrl = URL.createObjectURL(downfile); tmpLink.href = objectUrl; tmpLink.download = downfile.name; document.body.appendChild(tmpLink); tmpLink.click(); document.body.removeChild(tmpLink); URL.revokeObjectURL(objectUrl); } download(file);
如果是通过接口的形式获取文件流并生成下载文件,就可以参照以下 Vue 代码片段:
apiClient .get(apiFileUrl, { responseType: "arraybuffer", }) .then((response) => { const { headers, data } = response; const fileinfo = { blobData: data, fileName: ((strDispostion) => { if (strDispostion) { if ( strDispostion !== "" && strDispostion.split("filename=").length > 1 ) { return decodeURIComponent( strDispostion.split("filename=")[1] ); } else { return "tempname"; } } })(headers["content-disposition"]), }; const tmpLink = document.createElement("a"); const { blobData, fileName } = fileinfo; const blob = new Blob([blobData], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); const objectUrl = URL.createObjectURL(blob); tmpLink.href = objectUrl; tmpLink.download = fileName; document.body.appendChild(tmpLink); // 如果不需要显示下载链接可以不需要这行代码 tmpLink.click(); URL.revokeObjectURL(objectUrl); });