GoogleChrome78版本新的API让网页直接读写用户设备上的文件

JavaScript 无标签 2019-12-9 阅读:394

以前想在网页操作本地的文件是不是很麻烦?
包括现在的大多数上传文件都是用的input标签设置属性type="file"让用户选择一个文件进行上传

<input type="file" />

下载保存一个文件用a标签指定属性href为要下载的文件地址,download为下载文件名

<a href="xxxx.txt" download="文件名.txt">点击下载</a>

想要遍历一个本地的目录也是无法实现的,真的没办法了么?

不!Google Chrome78稳定版本它来了,带着新的实验性特性:Native File System,这是一个全新的本地文件读写 API,支持对文件的所有操作(读写创建删除),当然遍历目录也是没问题的。不过当前还未开发完成,预计将运行于Chrome80版本,因此默认并没有开启这项功能。

Native File System API 介绍

Native File System API 使开发人员能够构建功能强大的Web应用程序,以与用户本地设备上的文件进行交互。用户授予Web应用访问权限后,该API允许Web应用直接操作用户设备上文件和文件夹。

如果想要体验这个API的话,可以在地址栏输入 chrome://flags 进入后搜索 Native File System API 启用(Enabled)即可。

API用法

对文件的操作要用到window.chooseFileSystemEntries(option)

option参数解释:
option是一个对象,包含4个配置项:

属性说明类型默认值
type操作类型,是打开文件,保存文件还是打开文件夹,可选值为openFilesaveFileopenDirectoryStringopenFile
multiple允许用户选择单个文件还是选择多个文件,可选值为truefalseBooleanfalse
accepts指定弹出的文件选择框中允许选择的文件类型Object[]-
accepts.description描述String-
accepts.mimeTypes允许选择的文件的 MIME 类型String[]-
accepts.extensions允许选择的文件的扩展名String[]-
excludeAcceptAllOption是否允许选择不在上面 accepts 列表中允许的文件类型,默认允许选择任意文件Booleanfalse

读取文本内容

<button onclick="openFile()">打开文件</button>

async function openFile() {
    const handler = await window.chooseFileSystemEntries({
        type: 'openFile',
        accepts: [
            { description: '文本文件', extensions: ['txt'] }
        ]
    });

    const file = await handler.getFile();
    // 直接用file对象.text()可以获取文本内容(默认编码UTF-8)
    const text = await file.text();
    console.log(text);
    // 也可以用FileReader设置编码格式
    const reader = new FileReader();
    reader.onload =  event => {
        let contents = event.target.result;
        console.log(contents);
    };
    reader.readAsText(file, 'gbk');
}

保存文件

<button onclick="saveFile()">保存文件</button>

async function saveFile() {
    const handler = await window.chooseFileSystemEntries({
    type: 'saveFile',
    accepts: [
        { description: '文本文件', extensions: ['txt'] }
    ]
    });

    const writer = await handler.createWriter();
    // await writer.truncate(0);  // 清空文件
    await writer.write(0, 'Hello World!');  // 在文件头写入字符串
    await writer.close();
}

遍历目录

指定 optiontypeopenDirectory 可以指定打开一个文件夹,此时浏览器会向用户申请目录遍历权限,获得用户同意之后,就可以得到一个 FileSystemDirectoryHandle 对象

FileSystemDirectoryHandle 对象上拥有一个 getEntries() 函数,它返回一个异步迭代器,可以通过 for await ... of ... 循环对目录进行遍历。每次遍历得到的都是一个 FileSystemHandle 对象,可以根据 .isFile 属性与 .isDirectory 属性判断具体是 FileSystemFileHandle 对象还是 FileSystemDirectoryHandle 对象

除了使用 getEntries() 进行遍历,还可以通过 FileSystemDirectoryHandle 对象上的 getDirectory 函数打开一个指定的子目录,子目录同样是一个 FileSystemDirectoryHandle 对象,也可以通过 getFile 函数打开一个指定的文件,得到 FileSystemFileHandle 对象

<button onclick="directory()">遍历文件夹</button>

async function directory() {
    const handler = await window.chooseFileSystemEntries({
        type: 'openDirectory',
    });

    const ls = async (path, handler) => {
        const result = [];
        for await (const h of await handler.getEntries()) {
            if (h.isFile) {
                result.push(`${path}/${h.name}`);
            } else if (h.isDirectory) {
                const subDirectory = await ls(`${path}/${h.name}`, h);
                result.push(...subDirectory);
            }
        }
        return result;
    };

    const files = await ls(handler.name, handler);
    console.log(files);
}

安全性与权限

有了这么好用的API,安全性如何呢?(是不是可以偷偷读取用户设备上的小电影?向用户设备写入恶意文件?)当然是不能啦~

该API必须是通过用户的选择进行操作(也就是不能不经过用户同意后台自动执行)。

为了帮助保护用户及其数据,会限制保存到某些文件夹的,例如Windows等核心操作系统文件夹,macOS Library文件夹等。

必须用户授予Web程序操作文件权限,如果未获得用户的明确许可,Web应用程序将无法修改设备上的任何文件。

为了避免频繁地弹出权限警告,浏览器将会保存用户授予的权限,一旦用户授予网页访问某一文件,网页在被关闭之前都将拥有这个权限而不会过期。

一旦网页被关闭,所有的权限都将被回收,用户在下一次打开相同网站时,网站需要重新申请权限。

以上内容参考:

2条评论

    Him188moe

    cool

    游客 安卓 171 天前回复

      贤弟酱
      @Him188moe

      qaq蟹蟹啦

      作者 Windows10 171 天前回复