File System API前端文件系统API

文件系统API

在没有文件系统API之前,JS是不能对磁盘中的文件进行修改 写入磁盘的,有了File System API之后,就能对电脑设备磁盘中的文件进行修改,删除,创建(为了安全只能对非系统文件进行操作,且必须得到用户授权)

文件系统 API (File System API)------以及通过文件系统访问 API(File System Access API)提供的方法来访问设备中的文件或者文件夹,并可以对文件,文件夹进行创建,修改,等操作

注意:仅在部分浏览器支持


使用说明

大多数与文件和目录的交互都通过句柄来完成。通过调用全局方法来让用户选择文件,或者选择文件夹。之后就能得到这些 文件句柄对象,目录句柄对象,最后通过这些句柄对象来操作文件或目录

全局方法

打开文件对话框

方法window.showOpenFilePicker()用于打开一个文件选择器对话框,允许用户选择一个或者多个文件并返回这些文件的句柄

示例

js 复制代码
const pickerOpts = {
  types: [
    {
      description: "Images",
      accept: {
        "image/*": [".png", ".gif", ".jpeg", ".jpg"],
      },
    },
  ],
  excludeAcceptAllOption: true, // 是否开启过滤器
  multiple: false,  // 是否可多选文件
  startIn: 'desktop'  // ("desktop"、"documents"、"downloads"、"music"、"pictures" 或 "videos")以指定打开选择器的起始目录
};
async function getFile() {
  // 打开文件选择器,得到文件句柄列表数组
  const fileHandles = await window.showOpenFilePicker(pickerOpts);
  // 操作 fileHandle 的后续代码,具体看文件句柄章节
}

打开文件保存对话框

方法 window.showSaveFilePicker() 方法用于打开一个文件选择器,以允许用户保存一个文件。可以选择一个已有文件覆盖保存,也可以输入名字新建一个文件。

示例

js 复制代码
async function getNewFileHandle() {
  const opts = {
    types: [
      {
        description: "Text file",  // 默认文件名
        accept: { "text/plain": [".txt"] },
      },
    ],
    excludeAcceptAllOption: true, // 是否开启过滤器
    multiple: false,  // 是否可多选文件
    startIn: 'desktop'  // ("desktop"、"documents"、"downloads"、"music"、"pictures" 或 "videos")以指定打开选择器的起始目录
  };
  // 保存后得到文件句柄,之后可通过该文件句柄来写入数据,具体看文件句柄章节
  const fileHandle await window.showSaveFilePicker(opts);
  return fileHandle
}

打开目录对话框

方法window.showDirectoryPicker()方法用于打开一个目录选择器,以允许用户选择一个目录。之后得到该目录的句柄,通过这个句柄,可对该文件夹内的文件进行,删除,修改,创建新文件

示例

js 复制代码
const option = {
    mode: "readwrite", // 默认为 "read",用于只读访问,或 "readwrite" 用于读写访问
    startIn: 'desktop'  // 默认起始目录
}

async function getDir() {
  // 得到目录句柄
  const dirHandle = await window.showDirectoryPicker(option);
  // 通过句柄,可对文件夹内文件进行 增删改查
}

拖拽接收文件或目录

通过drop事件对象,调用getAsFileSystemHandle方法,得到一个 FileSystemFileHandle 文件对象句柄(若拖动的项目是文件)或 FileSystemDirectoryHandle 目录对象句柄(若拖动的项目是一个目录)

js 复制代码
elem.addEventListener("dragover", (e) => {
  e.preventDefault(); // 阻止导航
});
elem.addEventListener("drop", async (e) => {
  e.preventDefault();  // 阻止导航
  // 处理所有条目
  for (const item of e.dataTransfer.items) {
    // 对于文件/目录条目,kind 将是"file"
    if (item.kind === "file") {
      // 得到文件句柄,或者 目录句柄
      const entry = await item.getAsFileSystemHandle();
      if (entry.kind === "file") {
        // 收到的是文件
      } else if (entry.kind === "directory") {
        // 收到的是目录
      }
    }
  }
});

对象句柄

对象句柄由全局方法调用得到的,通过句柄对象能对文件或者目录进行一些操作

文件对象句柄

文件对象句柄FileSystemFileHandle 接口表示一个指向文件的句柄。可通过 window.showOpenFilePicker() 方法来得到文件对象句柄。

方法

以下方法基本都是得到一个Promise对象

读取文件

getFile()返回一个 File 对象。可读取文件内容

js 复制代码
// 打开文件选择器
const [fileHandle] = await window.showOpenFilePicker();

// 获取文件内容
const fileData = await fileHandle.getFile();
fileData.text()  // 得到文本内容

写入文件内容

createWritable()返回的是FileSystemWritableFileStream 文件流对象,可用于写入文件。

js 复制代码
// 打开文件选择器
const [fileHandle] = await window.showOpenFilePicker();

// 创建一个 FileSystemWritableFileStream 用来写入。
const writable = await fileHandle.createWritable();
// 将文件内容写入到流中。
await writable.write("要写入的内容");
// 关闭文件
await writable.close();

文件流对象句柄

FileSystemWritableFileStream 对象是对单个文件进行编辑的一些功能

方法

写入内容

write(),向此文件写入内容,写入到当前指针偏移处

js 复制代码
// 创建一个新句柄,得到文件句柄
const newHandle = await window.showSaveFilePicker();
// 创建一个 FileSystemWritableFileStream 用于写入
const writableStream = await newHandle.createWritable();
// 写入内容,支持ArrayBuffer、TypedArray、DataView、Blob 或字符串
await writableStream.write("This is my file content");
// 关闭文件并将内容写入磁盘
await writableStream.close();

移动指针位置

seek()移动指针位置,以字节为单位

js 复制代码
await writableStream.seek(100s)

修改文件为指定字节大小

truncate()将与流相关的文件修改为指定的字节大小

js 复制代码
await writableStream.truncate(1024);

目录对象句柄

目录对象句柄FileSystemDirectoryHandle,可对目录内的文件进行删除,读取,创建新文件。该句柄可通过window.showDirectoryPicker()全局方法获得

方法

获取目录内某个子目录的句柄

getDirectoryHandle()返回的是FileSystemDirectoryHandle目录对象句柄

js 复制代码
const dirName = "pic"  // 子目录名称
// create 代表,当目录不存在时,自动创建该目录。最后返回该目录的句柄
const dirHandle = currentDirHandle.getDirectoryHandle(dirName, { create: true })

获取目录内某个文件句柄

getFileHandle()方法返回的是FileSystemFileHandle文件对象句柄

js 复制代码
const dirName = "123.txt"  // 文件名称
// create 代表,当目录不存在时,自动创建该文件。最后返回该文件的句柄
const fileHandle = await dirHandle.getFileHandle(name, { create: true });

删除文件或者删除目录

removeEntry()

js 复制代码
// 默认不允许直接删除有文件的文件夹,recursive设置true,代表递归删除子文件
dirHandle.removeEntry('text.txt', { recursive: true });

获取目录内所有子文件句柄

values()

js 复制代码
const dirHandle = await window.showDirectoryPicker(); // 全局方法得到目录句柄
// 迭代获取每个文件句柄
for await (const value of dirHandle.values()) {
  console.log(value);
}

例子demo

读取文件内容

js 复制代码
const dirHandle = await window.showDirectoryPicker({
    readwrite: true,
    startIn: 'desktop'
});  // 打开一个目录,之后可对该目录内所有文件进行操作读取
// 读取该目录中的text.txt文件的内容
const fileBlob = await getFileContents(dirHandle, 'text.txt') 

async function getFileContents(dirHandle, name) {
    const fileHandle = await dirHandle.getFileHandle(name);
    const fileBlob = await fileHandle.getFile();
    const text = fileBlob.text();
    return text;
}

创建文件写入内容

js 复制代码
const dirHandle = await window.showDirectoryPicker({
    readwrite: true,
    startIn: 'desktop'
});  // 打开一个目录,之后可对该目录内所有文件进行操作读取

// 创建文件,写入内容
await createFile(dirHandle, 'text1.txt', "hello word");

async function createFile(dirHandle, name, contents) {
    const newFileHandle = await dirHandle.getFileHandle(name, { create: true });
    const writable = await newFileHandle.createWritable();
    await writable.write(contents);
    await writable.close();
}

重命名文件名

文件系统API本身并未提供修改文件名的方法,但是可以通过一些思路来实现

  1. 读取该文件内的内容
  2. 创建一个新的文件,设置新的文件名,然后将原来的内容写入,最后保存
  3. 删除原来的文件
js 复制代码
// 重命名文件
async function renameFile() {
    // 打开目录,会弹窗用户授权
    const dirHandle = await window.showDirectoryPicker({
        readwrite: true,
        startIn: 'desktop'
    });
    const originName = "text.txt"  // 原文件名
    const newName = "text-ok.txt"  // 新文件名
    // 读取源文件内容
    const fileBlob = await getFileContents(dirHandle, originName)
    // 创建新文件,按新文件名保存
    await createFile(dirHandle, newName, fileBlob);
    // 删除源文件
    dirHandle.removeEntry(originName, { recursive: true });
}
// 创建新文件并写入内容
async function createFile(dirHandle, name, contents) {
    const newFileHandle = await dirHandle.getFileHandle(name, { create: true });
    const writable = await newFileHandle.createWritable();
    await writable.write(contents);
    await writable.close();
}
// 读取文件内容blob
async function getFileContents(dirHandle, name) {
    const fileHandle = await dirHandle.getFileHandle(name);
    const fileBlob = await fileHandle.getFile();
    return fileBlob;
}
相关推荐
卸任9 小时前
Vibe coding工具使用心得
前端·ai编程
brien99 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance10 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M10 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写10 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李10 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易10 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding10 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马10 小时前
前沿视界
前端
kyriewen10 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员