ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Puter 文件系统删除详解:puter.fs.delete() 的调用形式、递归语义与底层实现

Puter 文件系统删除详解:puter.fs.delete() 的调用形式、递归语义与底层实现 Puter 文件系统删除详解puter.fs.delete() 的调用形式、递归语义与底层实现【免费下载链接】puter The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puterputer.fs.delete()是 Puter 云文件系统Cloud Storage API中用于删除文件或目录的核心方法适用于 websites、apps、nodejs 与 workers 四类平台。本文以官方 API 文档 delete.md 为骨架结合 Puter JS SDK 与 后端 FS 控制器 的源码系统讲解它的全部调用形式、参数语义、返回值与错误处理并深入分析“递归删除”“仅删除子项”两个选项在前后端的真实实现帮助你安全、精确地完成各类删除操作。功能概览与适用平台puter.fs.delete()用于删除用户在 Puter 云文件系统中自己的文件或目录。一次调用既可删除单个对象也可批量删除多个文件与目录。它在 SDK 模块中的挂载位置位于 FileSystem/index.js。值得注意的是内部实现函数命名为deleteFSEntry而非delete源码注释给出了直接原因delete是 JavaScript 的保留关键字不能直接用作标识符因此对外暴露为puter.fs.delete。// 在 index.js 中的挂载方式节选 delete deleteFSEntry; // 见 index.js 第 52-54 行注释该方法在以下平台均可使用对应文档 frontmatter 中platforms字段平台说明websites通过script srchttps://js.puter.com/v2/引入浏览器 SDK 的网页appsPuter 生态内运行的应用nodejsNode.js 服务端或脚本workersPuter 的 Worker 运行时删除属于写操作会消耗与目录创建、移动等操作相同的写配额/速率限制策略见下文后端分析因此不适合在高频循环中无节制调用。方法签名与三种调用形式文档定义了三种等价语法puter.fs.delete(paths); puter.fs.delete(paths, options); puter.fs.delete(options);从 deleteFSEntry.js 的类型重载可以看到SDK 实际支持更完整的四种调用约定其中第三种形式还兼容旧式回调puter.fs.delete(options) // 仅传 options 对象 puter.fs.delete(paths, options, success?, error?) // 位置参数 可选回调 puter.fs.delete(paths, success?, error?) // 省略 options直接接回调这套“统一调用约定”由操作脚手架 scaffold.js 中的parseOperationArgs实现当第一个参数是“对象形状”的值非数组、非 File/Blob时按 options 形式解析否则按位置参数解析并将后续的函数实参分别绑定为success/error回调。下面逐一展开三种主要形式位置参数形式最常见第一个参数传路径或路径数组第二个可选参数传 options 对象。纯 options 形式将路径放进 options 的paths字段此时paths为必填。混合形式路径 options 传统的success/error回调用于不习惯 Promise 的老代码风格Promise 与回调会同时生效。参数详解pathsString | String[]必填待删除的文件或目录路径可以是单个路径字符串也可以是路径数组数组即批量删除若传入相对路径SDK 会先将其解析为基于“应用根目录”apps root directory的绝对路径再发起请求路径解析由工具函数getAbsolutePathForApp完成见 deleteFSEntry.js 中的paths.map((path) getAbsolutePathForApp(path))在纯 options 形式中paths必须作为 options 的字段传入否则没有可删除的目标。optionsObject可选支持以下选项与类型定义 types.js 中的DeleteOptionsOwn完全对应选项类型默认值说明pathsString | String[]—待删除的路径可单个可批量。仅当以 options 作为唯一参数调用时必填。recursiveBooleantrue是否递归删除目录。SDK 层默认true。descendantsOnlyBooleanfalse是否只删除目录的全部子项而保留目录本身。默认false即连同目录一并删除。兼容性细节SDK 在解析descendantsOnly时使用了firstDefined工具见 deleteFSEntry.js它会同时接受descendantsOnly与历史下划线写法descendants_only先到先得recursive则直接用options.recursive ?? true兜底。因此你的历史代码如果使用了蛇形命名依然可以正常工作。两个选项的语义边界recursive: false 目录内还有内容只尝试删除目录本身非空目录会因包含子项而失败recursive: true默认则会清空目录树后删除整个目录。descendantsOnly: true效果是“清空目录但保留目录外壳”典型的应用场景是保留目录节点本身例如回收站、容器目录等需要继续存在的结构。此时recursive决定清空时是否深入嵌套子目录。返回值与错误处理方法返回一个Promise在文件或目录被删除后 resolve解析值本身为空类型上表现为Promisevoid见 types.js 中DeleteOptionsOwn RequestCallbacksvoid的组合。错误路径需要注意以下几点认证失败如果用户未登录且当前不是 web 环境请求会直接被拒绝。脚手架中ensureAuthenticatedscaffold.js在检测不到 token 时会抛出Authentication failed.浏览器环境下会先弹出 Puter 授权流程。存储/配额类错误当后端因存储限制拒绝写操作时SDK 会走rejectWithPrompt分支scaffold.js弹出与“配额已满的上传”一致的用户升级提示同时以 reject 形式通知调用方。无论是否附带success/error回调Promise 的 resolve/reject 值都与回调收到的值保持一致二者不会相互矛盾。完整示例示例一删除一个文件以下示例先写入一个随机文件再将其删除继承自文档并保留完整可运行结构html body script srchttps://js.puter.com/v2//script script (async () { // (1) Create a random file let filename puter.randName(); await puter.fs.write(filename, Hello, world!); puter.print(File created successfullybr); // (2) Delete the file await puter.fs.delete(filename); puter.print(File deleted successfully); })(); /script /body /html对于单文件删除recursive与descendantsOnly均无实际影响可全部省略。文件写入与目录创建的细节可分别参考 write.md 与 mkdir.md。示例二删除一个目录先mkdir建一个随机目录再整个删除默认即递归目录内的任何内容都会被一并清除html body script srchttps://js.puter.com/v2//script script (async () { // (1) Create a random directory let dirname puter.randName(); await puter.fs.mkdir(dirname); puter.print(Directory created successfullybr); // (2) Delete the directory await puter.fs.delete(dirname); puter.print(Directory deleted successfully); })(); /script /body /html示例三批量删除多个文件paths支持数组形式一次请求删除多个对象// 单个字符串 await puter.fs.delete(/photos/cat.png); // 字符串数组一次删除多个文件 await puter.fs.delete([ /photos/cat.png, /photos/dog.png, /notes/todo.txt, ]);示例四清空目录但保留目录本身当需要“清掉目录下所有内容却保留该目录”时使用descendantsOnly: true同时显式指定recursive: trueSDK 默认即为true以保证嵌套子目录也被递归清空// 删除 my-projects 下的所有子项但保留 my-projects 目录本身 await puter.fs.delete(/my-projects, { recursive: true, descendantsOnly: true, }); // 位置参数 options 的等价写法 await puter.fs.delete(/my-projects, { descendantsOnly: true });示例五仅删除目录自身非空则失败强制“浅删除”并观察非空目录的失败行为try { // 目录非空时该调用会 reject await puter.fs.delete(/non-empty-dir, { recursive: false }); console.log(目录已删除); } catch (e) { console.error(删除失败目录可能非空:, e); }示例六仅传 options 对象当以 options 作为唯一参数时路径必须放入paths字段该用法在 operations.test.js 中有专门用例验证它会被转换为与位置参数形式完全一致的请求体await puter.fs.delete({ paths: /a/dir, recursive: false, }); // 等价于 await puter.fs.delete(/a/dir, { recursive: false });相对路径解析规则与 Puter FS 其他方法一致delete遵循同一套路径语义绝对路径如/photos/cat.png直接定位到用户在 Puter 云盘中的对应位置相对路径如cat.png或./cat.png会被getAbsolutePathForApp解析为“基于当前应用根目录”的绝对路径因此应用只能删除自己目录树内的内容天然起到隔离作用。关于 FS 路径模型更完整的说明可参考同目录下的 stat.md、move.md 与 readdir.md。源码视角一次删除请求在 SDK 内如何产生deleteFSEntry是借助defineOperation脚手架声明的deleteFSEntry.js其核心逻辑非常精简const deleteFSEntry defineOperation({ positional: [paths], request (options) { // 单个路径无需调用方手动包成数组 const paths Array.isArray(options.paths) ? options.paths : [options.paths]; return { endpoint: /delete, body: { paths: paths.map((path) getAbsolutePathForApp(path)), descendants_only: firstDefined(options, descendantsOnly, descendants_only) ?? false, recursive: options.recursive ?? true, }, }; }, });可以看到 SDK 侧完成的三件事归一化将单个字符串路径统一包装成数组减小后端处理分支路径翻译所有相对路径在执行前统一换算为绝对路径默认值注入recursive缺省为true、descendants_only缺省为false并将 camelCase 与蛇形别名收敛为descendants_only后随请求体发送。随后脚手架以默认 POST 方法向${APIOrigin}/delete发起带鉴权头的 XHR 请求见 scaffold.js。deleteFSEntry之所以只描述“endpoint body”是因为鉴权、Promise 化、错误提示等通用逻辑全部由脚手架承担——这也是整个 FileSystem 模块二十余个操作采用的一致设计。后端视角/delete 路由的权限与处理流程浏览器 SDK 最终调用的后端路由定义在 FSController.tsPost(/delete, { subdomain: api, requireVerified: true, rateLimit: FS_MUTATE_LIMIT, }) async deleteEntry(req: Request, res: Response) { const actor this.#requireActor(req); const userId this.#getActorUserId(req); const body this.#toObjectRecord(req.body); const entry await this.#resolveEntryForRequest(body); await this.#assertAccess(actor, entry.path, write); const descendantsOnly this.#toBoolean(body.descendants_only) ?? false; await this.services.fs.remove(userId, { entry, recursive: this.#toBoolean(body.recursive) ?? false, descendantsOnly, }); this.#emitGuiItemRemoved(entry, descendantsOnly); res.json({ ok: true }); }从这段实现可以提炼出若干可验证的事实认证与准入路由要求requireVerified: true邮箱已验证的用户并受到FS_MUTATE_LIMIT这一写操作速率限制的约束权限模型删除前执行#assertAccess(actor, entry.path, write)即对目标路径要求write写权限而非独立的管理员权限关键默认值差异后端解析recursive时缺省为false?? false。这与 SDK 默认发送true并不矛盾——正因为 SDK 在每次请求中都会显式注入默认值recursive: true文档层面才呈现“默认递归删除”的语义如果你绕过 SDK 直接构造 HTTP 请求且不携带该字段则会得到“非递归”行为。理解这一差异有助于排查“为什么目录没被删掉”之类的问题广播更新删除成功后调用#emitGuiItemRemoved(entry, descendantsOnly)通知 GUI 层在descendants_only场景下保留父目录节点的 UI 状态并统一返回{ ok: true }。测试证据仓库中的 operations.test.js 为 delete 语义提供了自动化保障主要用例包括fs.delete(/a/file.txt)会向https://api.test/delete发起请求请求体默认携带descendants_only: false, recursive: true验证了默认值fs.delete([/a/one.txt, /a/two.txt])验证路径数组被完整透传fs.delete(/a/dir, { recursive: false, descendantsOnly: true })验证 options 会以recursive: false, descendants_only: true的形态进入请求体即 camelCase → snake_case 的字段映射正确fs.delete({ paths: /a/dir, recursive: false })验证纯 options 形式与位置参数形式最终产生一致的请求结构。这些用例是文档所宣称“默认值”与“两种调用形式等价”的直接代码级佐证。后端侧行为则可结合 FSController.ts 以及其配套的 FSController.test.ts 深入验证。实践建议与注意事项删除不可撤销puter.fs.delete()是直接删除语义建议对批量删除先通过 readdir.md 或 stat.md 列出目标内容做二次确认用好descendantsOnly需要“保留容器目录”时例如保留项目的根目录结构、只清空产出物这是比“先删目录再建目录”更原子、更不易出错的方案批量删除是数组语义对超过一个目标时务必传字符串数组单个路径也可以直接传字符串SDK 会统一归一化注意递归与后端默认值的差异直接调用 HTTP API 时若省略recursive后端按false处理使用 SDK 则默认true。接口对接时要显式携带该字段以免歧义回调与 Promise 二选一或混用老代码可继续传success/error回调新代码建议统一使用await两者获得的值完全一致路径安全相对路径受应用根目录约束跨应用删除他人文件会在权限层被write校验拦截。若想进一步掌握 Puter FS 全貌推荐继续阅读同目录下的 upload.md、write.md、copy.md 与 move.md并结合 FileSystem/index.js 与 FSController.ts 做前后端对照学习。【免费下载链接】puter The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表