读取文件内容、修改文件内容、识别文件夹目录(Web操作系统文件文件夹详解)

前言

因 Unicode IDE 编辑器导入文件、文件夹需要,研究了下导入文件/文件夹的功能实现,发现目前相关文章有点少,故而记录下过程,如果有误,还望指正。(API的兼容性及相关属性、接口定义,请自行查看文件系统 API)

文件 API

文件 API 使得 web 应用可以访问文件和其中的内容,当我们想要访问一个文件,可以通过[](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input/file “”)或者拖放来实现。以这种方式提供的文件集被表示为FileList对象,这使得 web 应用能够检索单个File对象。

  const input = document.createElement("input");input.type = "file";input.multiple = true;input.addEventListener("change", () => {// 当然,此处也可以使用事件源 e 来获取 FileList 对象哈,e.target 指向 inputconst fileList = input.files;console.log("==> ", fileList);});input.click();

Blob

Blob 代表“二进制大对象”(类似于文件的不可变的原始数据对象);Blob可以作为文本或二进制数据被读取,或者转换为ReadableStream。我们常用来处理大文件数据分片,里面有一个Blob.slice()方法,用于获取指定字节范围内的数据。

  input.addEventListener("change", () => {// 当然,此处也可以使用事件源 e 来获取 FileList 对象哈,e.target 指向 inputconst fileList = input.files;// 以第一个 File 对象为例,获取 Blobconst file = fileList![0];const blob = new Blob([file], { type: file.type });console.log("==> ", blob);});

File

File对象提供对元数据的访问,如文件的名称、大小、类型和最后修改日期提供文件的信息,并允许网页中的 JavaScript 代码访问其中的内容,通常利用File进行内容读取、进行网络传输等。

FileReader

使 web 应用能够异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用File或Blob对象来指定要读取的文件或数据。

通常,FileReader 是异步的,因为读取文件内容是需要时间的,因此,可以通过监听 load 实现读取成功完成时回调处理。读取文件还能将文件读成多种结果类型:

  input.addEventListener("change", () => {// 当然,此处也可以使用事件源 e 来获取 FileList 对象哈,e.target 指向 inputconst fileList = input.files;// 以第一个 File 对象为例,获取 Blobconst file = fileList![0];const fileReader = new FileReader();fileReader.onload = () => {console.log(fileReader.result);};fileReader.readAsText(file);});

Tips:关于上诉 FileReader、Blob、File等常见数据类型的定义、转换不在本篇的讨论范围哈,网上也有很详细的说明,大家搜索一下就可以了,我推荐两篇文章,大家可以看看~

谈谈JS二进制:File、Blob、FileReader、ArrayBuffer、Base64[这里是图片006]https://juejin.cn/post/7148254347401363463?searchId=20241113152541CCE5E6FEB74927A4CFEBjs二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL…)[这里是图片007]https://juejin.cn/post/7395866692798201871?searchId=20241113152055D9FE2B4CE63230A35055

文件系统 API

用户直接操作系统文件是非常危险的行为,因此,此API要求在安全上下文可用。

File System API 允许程序与用户本地设备上的或是用户能够访问的网络文件系统上的文件进行交互。此 API 的核心功能包括读取文件、写入或保存文件以及访问目录结构。大多数与文件和目录的交互都通过句柄来完成:

句柄是指在Web API中用于操作文件系统的接口或对象。

通过这些句柄,Web应用可以实现对本地文件系统的读取、写入、导航等操作。

File System API允许Web应用在用户的设备上创建、读取、导航用户本地文件系统中的沙盒部分,并向其中写入数据。

**FileSystemHandle**接口是代表一个文件或一个目录的对象,在大多数情况下,你不会直接使用FileSystemHandle,而是会用到它的FileSystemFileHandle和FileSystemDirectoryHandle子接口。

文件处理

文件处理最简单的就是 input file了,这里就不演示了,**?FileSystemFileHandle**接口表示一个指向文件系统条目的句柄。可通过window.showOpenFilePicker()方法来访问此接口:

  try {// 通过文件选择器获取文件const file = await window.showOpenFilePicker();console.log("==> ", file);} catch (error) {console.error(error);}

如上演示效果,尽管已经可以调用文件,但是 ts 还是报错了,可以通过自定义 Window 的接口来解决这个问题,明确告诉window上存在这个方法即可,还可以拓展一些其他的属性,便于后期的操作哈~

window.showOpenFilePicker() 返回的结果是一个Promise<FileSystemFileHandle[]>是个数组,我们应该如何获取该文件的具体内容呢?

读取文件内容

FileSystemFileHandle有一个getFile方法,用于返回一个 File 对象,有了这个对象,剩下的就是创建 FileReader 读取就可以啦

  try {// 通过文件选择器获取文件const fileListHandle = await window.showOpenFilePicker();fileListHandle.forEach(async (fileHandle) => {const file = await fileHandle.getFile();const fileReader = new FileReader();fileReader.readAsText(file);fileReader.onload = () => {const text = fileReader.result;console.log("==> 文件内容", text);};});} catch (error) {console.error(error);}

写入文件

上面演示了如何读取文件内容,那么,我们该如何修改文件内容呢?createWritable()方法用于创建一个FileSystemWritableFileStream对象,可用于写入文件。

  try {// 通过文件选择器获取文件const fileListHandle = await window.showOpenFilePicker();//  拿第一个文件做演示哈const fileHandle = fileListHandle[0];// 创建写入句柄const writable = await fileHandle.createWritable();// 将文件内容写入到流中。await writable.write(`当前时间:${getDate()}`);// 关闭文件并将内容写入磁盘。await writable.close();console.log("==> 写入文件成功");} catch (error) {console.error(error);}

还有同步写入的方法createSyncAccessHandle,这里就不演示了哈。如果写入的文件系统有权限要求,可能需要在获取句柄时,查询权限参数。

文件夹处理

**FileSystemDirectoryHandle**接口提供指向一个文件系统目录的句柄。这个接口可以通过window.showDirectoryPicker()、

StorageManager.getDirectory()、

DataTransferItem.getAsFileSystemHandle()、

FileSystemDirectoryHandle.getDirectoryHandle()这些方法来获取。

因此,文件夹的处理方式要多一些,FileSystemDirectoryHandle.getDirectoryHandle() 与第一个有重叠部分,因此本文仅讲解第一种(点击上传)、第三种(拖拽上传)方式获取文件夹句柄。(第二种是Web Worker)

点击上传文件夹
  try {//  获取文件夹句柄const dirHandle = await window.showDirectoryPicker();console.log("==> ", dirHandle);} catch (error) {}

window.showDirectoryPicker() 会返回一个文件夹句柄,里面有几个关键的函数:getDirectoryHandle、getFileHandle、迭代器。

    //  获取文件夹句柄const dirHandle = await window.showDirectoryPicker();for await (const item of dirHandle.values()) {console.log("==> ", item);}

如果是文件的话,就获取文件句柄,如果是文件夹的话,就获取文件夹句柄,递归直到读取完成:

function directoryPickerHandle(files: FileSystemDirectoryHandle) {const reader = new FileReader();// 2. 递归解析文件夹内容async function entryFolder(handle: FileSystemDirectoryHandle) {for await (const item of handle.values()) {// 判断文件还是文件夹if (item.kind === "file") {// 创建文件读取器, 会返回 FileSystemFileHandleconst fileHandle = await handle.getFileHandle(item.name);// 调用 getFile() 获取文件对象(File)const file = await fileHandle.getFile();const fullpath =(handle.parentName || "") + "/" + handle.name + "/" + file.name;console.log("==> 文件完整路径:", fullpath);// 创建 Reader 读取器,读取文件内容reader.onload = () => {};reader.readAsText(file, "UTF-8");} else if (item.kind === "directory") {// 创建文件夹读取器,返回 FolderSystemHandleconst folderHandle = await handle.getDirectoryHandle(item.name);const fullpath = handle.name + "/" + item.name;// 记录该路径folderHandle.parentName = handle.name;console.log("==> 文件夹完整路径:", fullpath);entryFolder(folderHandle);}}}// 3. 启动entryentryFolder(files);
}

这样就能识别文件夹内的所有目录、文件内容啦。这里面有一个注意事项哈:const folderHandle = await handle.getDirectoryHandle(item.name); 这里创建的getDirectoryHandle 恰好就是 类型四返回的文件夹句柄,又转向递归,实现读取文件夹操作

拖拽上传文件夹

DataTransferItem接口的**getAsFileSystemHandle()**方法返回一个FileSystemFileHandle(若拖动的项目是文件),或FileSystemDirectoryHandle(若拖动的项目是目录)。

拖拽上传需要设置HTMLdraggable=“true”,并且监听三个事件:

window.onload = () => {const box = document.querySelector(".box");box?.addEventListener("dragenter", (e) => e.preventDefault());box?.addEventListener("dragover", (e) => e.preventDefault());box?.addEventListener("drop", (e: Event) => {// 阻止导航e.preventDefault();const event = <DragEvent>e;// 获取拖拽的数据console.log("==> ", event.dataTransfer);});
};

咋一看好像结果为空,明明拖拽文件夹了,结果集还是空的,那是因为你放手的瞬间,数据传输已经完成了。

  box?.addEventListener("drop", (e: Event) => {// 阻止导航e.preventDefault();const event = <DragEvent>e;const items = event.dataTransfer?.items;if (!items) return;for (const item of items) {// 获取文件系统句柄const entry = item.webkitGetAsEntry()!;console.log("==> ", entry);}});

当你拖拽文件和拖拽文件夹时,是不同的数据类型哦,注意一下

拖拽的是文件的话,可以调用 files() 进行文件读取

    const fileEntry = <FileSystemFileEntry>entry;fileEntry.file((file: File) => {// 创建 fileReaderconst reader = new FileReader();reader.readAsText(file, "UTF-8");reader.onload = async () => {};});

拖拽的是文件夹的话,递归继续调用

    // 文件夹,创建读取器const folderRntry = <FileSystemDirectoryEntry>entry;// 记录需要创建的文件夹路径console.log("==> 记录文件夹路径", folderRntry.fullPath);const reader = folderRntry.createReader();reader.readEntries((files) => {files.forEach((file) => dataTransferHandle(file));});

如果想要实现记录完整文件名称的话,可以跟上诉示例一样,自定义parentName 实现。

总结

我们通过FileSystemFileHandle可以进行文件内容读取、修改文件内容等文件相关操作,同时,利用FileSystemDirectoryHandle提供的能力,可以实现点击上传并识别文件夹目录,对文件夹内文件进行内容读取,还利用DataTransferItem,实现了拖拽上传文件/文件夹,利用其能力,也能识别文件夹目录及对文件进行读取操作。同时,拖拽上传还支持纯文本哈,const data = e.dataTransfer.getData(“text”); 这也是一些白板、Canvas-Editor、流程图 从外部拖拽上传实现的原理。

再次声明哈,该API具有一定兼容性差异,请查阅MDN后,再决定使用生产,同时,请一定确保使用备用方案,以实现功能的完整性。同时,该文章仅表示本人应用过程实践,可能存在遗漏、错误,烦请指正赐教~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/890672.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第6章 图论

2024年12月25日一稿 &#x1f430;6.1 图的基本概念 6.1.1 图的定义和表示 6.1.2 图的同构 6.1.3 完全图与正则图 6.1.4 子图与补图 6.1.5 通路与回路 6.2 图的连通性 6.2.1 无向图的连通性 6.2.2 有向图的连通性 6.3 图的矩阵表示 6.3.1 关联矩阵 6.3.2 有向图的邻接矩阵…

网络管理(Network Management,NM)(一)

1.什么是AUTOSAR的网络管理&#xff1f;为什么要网络管理 ? 2.网络管理的三种模式&#xff1f; 上电时&#xff0c;进入总线睡眠模式&#xff0c;如果有唤醒源唤醒&#xff0c;则进入网络模式。其中。唤醒源唤醒分为主动唤醒和被动唤醒&#xff0c;主动唤醒指的是ecu自己想使…

三维扫描在汽车/航空行业应用

三维扫描技术应用范围广泛&#xff0c;从小型精密零件到大型工业设备&#xff0c;都能实现快速、准确的测量。 通过先进三维扫描技术获取产品和物体的形面三维数据&#xff0c;建立实物的三维图档&#xff0c;满足各种实物3D模型数据获取、三维数字化展示、3D多媒体开发、三维…

机器学习实战32-利用机器学习对电商销售数据进行归因分析的方法,旨在找出销量下降的原因

大家好,我是微学AI,今天给大家介绍一下机器学习实战32-利用机器学习对电商销售数据进行归因分析的方法,旨在找出销量下降的原因。文章详细介绍了代码编写过程、应用场景及其具体操作,通过实际案例分析,帮助读者深入了解如何运用机器学习技术对电商销售数据进行分析,从而为…

录播检测原理是什么?

直播间录播的检测可以通过多种方式进行。以下是一些常见的检测方法&#xff1a; 1、水印识别&#xff1a;直播平台可以在实时直播画面中嵌入特定的水印&#xff0c;通过识别水印来判断是否存在录播行为。 2、特征分析:直播平台可以通过对直播画面进行特征分析&#xff0c;检测…

WebSocket | 背景 概念 原理 使用 优缺点及适用场景

1 背景 在 WebSocket 出现之前&#xff0c;为了实现推送技术&#xff0c;所用的技术都是轮询&#xff0c;轮询是指浏览器每隔一段时间向服务器发出 HTTP 请求&#xff0c;服务器再返回最新的数据给客户端 常见的轮询方式分为轮询与长轮询&#xff0c;它们的区别如下图所示&…

硬件设计-传输线匹配

目录 简介&#xff1a; 主题&#xff1a; 终端匹配 始端匹配 始端匹配的阻值 始端匹配的输出驱动电流 中间匹配 电阻阻值的选择 简介&#xff1a; 系统何时需要匹配电阻&#xff1f;按照第四章的内容来看有两种情况&#xff1a;长线传输造成信号反射的情况和短线传输造成…

设计模式的主要分类是什么?请简要介绍每个分类的特点。

大家好&#xff0c;我是锋哥。今天分享关于【设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。】面试题。希望对大家有帮助&#xff1b; 设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。 1000道 互联网大厂Java工程师 精选面试题-Java资源分…

基于微信小程序的校园访客登记系统

基于微信小程序的校园访客登记系统 功能列表 用户端功能 注册与登录 &#xff1a;支持用户通过手机号短信验证码注册和登录。个人资料管理 &#xff1a;允许用户编辑和更新个人信息及其密码。站内信消息通知&#xff1a;通知公告。来访预约&#xff1a;提交来访预约支持车牌…

重温设计模式--观察者模式

文章目录 观察者模式&#xff08;Observer Pattern&#xff09;概述观察者模式UML图作用&#xff1a;实现对象间的解耦支持一对多的依赖关系易于维护和扩展 观察者模式的结构抽象主题&#xff08;Subject&#xff09;&#xff1a;具体主题&#xff08;Concrete Subject&#xf…

CH32V307VCT6---工程template创建

一、硬件&#xff1a;沁恒官网申请的CH32V307VCT6开发板 二、开发环境&#xff1a;Mounriver 三、最终效果 1.PB9连接LED1&#xff0c;使其闪烁 2.OLED屏幕显示&#xff1a;软件IIC&#xff0c;PB10----SDA&#xff0c;PB11---SCL 3.工程链接&#xff1a;CH32V307VCT6 lo…

分布式协同 - 分布式事务_2PC 3PC解决方案

文章目录 导图Pre2PC&#xff08;Two-Phase Commit&#xff09;协议准备阶段提交阶段情况 1&#xff1a;只要有一个事务参与者反馈未就绪&#xff08;no ready&#xff09;&#xff0c;事务协调者就会回滚事务情况 2&#xff1a;当所有事务参与者均反馈就绪&#xff08;ready&a…

【软考高级】系统架构设计师复习笔记-精华版

文章目录 前言0 系统架构设计师0.1 考架构还是考系分0.2 架构核心知识0.3 架构教材变化 1 计算机操作系统1.1 cpu 组成1.2 内核的五大功能1.3 流水线技术1.4 段页式存储1.5 I/O 软件1.6 文件管理1.7 系统工程相关 2 嵌入式2.1 嵌入式技术2.2 板级支持包&#xff08;BSP&#xf…

图解HTTP-HTTP报文

参考资料&#xff1a;图解HTTP HTTP报文 用于HTTP协议交互的信息被称为HTTP报文。请求端的HTTP请求报文&#xff0c;响应端&#xff08;服务器端&#xff09;的叫做响应报文。HTTP报文本身是由多行&#xff08;CR LF作为换行符&#xff09;数据行构成的文本。 请求报文及响…

Linux -- 同步与条件变量

目录 同步 条件变量 pthread_cond_t pthread_cond_init&#xff08;初始化条件变量&#xff09; pthread_cond_destroy&#xff08;销毁条件变量&#xff09; pthread_cond_wait&#xff08;线程等待条件变量&#xff09; 重要提醒 pthread_cond_boardcast&#xff08…

【源码编译】windows下mingw64安装以及cmake调用

最近因为安装MIRTK库&#xff0c;太多第三方依赖了&#xff0c;太折磨了&#xff0c;学习了使用Cmake&#xff0c;有些库又需要Fortran编译器&#xff0c;VS2022里面装了但又调用不了&#xff0c;也不知道为什么&#xff0c;最后装的mingw64&#xff0c;记录一下。 1、mingw64安…

6、mysql的MHA故障切换

MHA的含义 MHA&#xff1a;master high availability&#xff0c;建立在主从复制基础上的故障切换的软件系统。 主从复制的单点问题&#xff1a; 当主从复制当中&#xff0c;主服务器发生故障&#xff0c;会自动切换到一台从服务器&#xff0c;然后把从服务器升格成主&…

LeetCode:104.二叉树的最大深度

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;104.二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节…

WebRTC服务质量(12)- Pacer机制(04) 向Pacer中插入数据

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

双指针——快乐数

一.题目描述 202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 二.题目解析 我们要判断一个数是不是快乐数要通过它的三个性质来进行判断。这个数会一直变化&#xff0c;由它的各个位的平方和重新构成这个数。如果这个数在变化的过程中变成了1&#xff0c;那么就是快乐数…