文件系统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本身并未提供修改文件名的方法,但是可以通过一些思路来实现
- 读取该文件内的内容
- 创建一个新的文件,设置新的文件名,然后将原来的内容写入,最后保存
- 删除原来的文件
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;
}