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

前言

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

 文件 API

        文件 API 使得 web 应用可以访问文件和其中的内容,当我们想要访问一个文件,可以通过<input type="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、Base64icon-default.png?t=O83Ahttps://juejin.cn/post/7148254347401363463?searchId=20241113152541CCE5E6FEB74927A4CFEBjs二进制及其相关转换全总结(File、Blob、FileReader、ArrayBuffer、Base64、Object URL、DataURL...)icon-default.png?t=O83Ahttps://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(若拖动的项目是目录)。

拖拽上传需要设置HTML  draggable="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/886166.shtml

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

相关文章

【卡尔曼滤波】数据融合Fusion的应用 C语言、Python实现(Kalman Filter)

【卡尔曼滤波】数据融合Fusion的应用 C语言、Python实现&#xff08;Kalman Filter&#xff09; 更新以gitee为准&#xff1a; gitee地址 文章目录 卡尔曼滤波数据融合Python实现C语言实现多个数据如何融合附录&#xff1a;压缩字符串、大小端格式转换压缩字符串浮点数压缩Pac…

docker-hub 无法访问,使用windows魔法拉取docker images再上传到linux docker环境中

云机的服务器是可以docker拉取镜像的&#xff0c;但是本地的虚拟机、物理服务器等网络环境不好的情况&#xff0c;是无法访问docker-hub的&#xff0c;即使更换了docker镜像源国内源也无法使用。 本文章使用 在魔法网络环境下的windows&#xff0c;下载docker images后&#xf…

Python →爬虫实践

爬取研究中心的书目 现在&#xff0c;想要把如下网站中的书目信息爬取出来。 案例一 耶鲁 Publications | Yale Law School 分析网页&#xff0c;如下图所示&#xff0c;需要爬取的页面&#xff0c;标签信息是“<p>”&#xff0c;所以用 itemssoup.find_all("p&…

【Linux学习】【Ubuntu入门】1-4 ubuntu终端操作与shell命令1

1.使用快捷键CtrlAltT打开命令终端&#xff0c;或者单击右键点击… 2.常用shell命令 目录信息查看命令&#xff1a;ls ls -a&#xff1a;显示目录所有文件及文件夹&#xff0c;包括隐藏文件&#xff0c;比如以.开头的 ls -l&#xff1a;显示文件的详细信息 ls -al&#xff1…

WordPress 6.7 “Rollins”发布

每个 WordPress 版本都会向一位在音乐界留下不可磨灭印记的艺术家致敬。WordPress 6.7 的代号为“Rollins”&#xff0c;旨在向传奇爵士萨克斯演奏家桑尼罗林斯致敬。罗林斯是爵士乐界最伟大的即兴演奏家和先驱之一&#xff0c;他以精湛的技术、创新精神和无畏的音乐表达方式影…

ESXi安装【真机和虚拟机】(超详细)

项目简介&#xff1a; ESXi&#xff08;Elastic Sky X Integrated&#xff09;是VMware公司开发的一种裸机虚拟化管理程序&#xff0c;允许用户在单一物理服务器上运行多个虚拟机&#xff08;VM&#xff09;。它直接安装在服务器硬件上&#xff0c;而不是操作系统之上&#xff…

【若依框架】代码生成详细教程,15分钟搭建Springboot+Vue3前后端分离项目,基于Mysql8数据库和Redis5,管理后台前端基于Vue3和Element Plus,开发小程序数据后台

今天我们来借助若依来快速的搭建一个基于springboot的Java管理后台&#xff0c;后台网页使用vue3和 Element Plus来快速搭建。这里我们可以借助若依自动生成Java和vue3代码&#xff0c;这就是若依的强大之处&#xff0c;即便你不会Java和vue开发&#xff0c;只要跟着石头哥也可…

HBuilder(uniapp) 配置android模拟器

HBuilder&#xff08;uniapp&#xff09; 配置android模拟器 选择完成之后&#xff0c;点击ok&#xff0c;再次点击Configure—》AVD Manager

flutter插件:录制系统播放的声音

该插件基于flutter包 flutter_screen_recording 和 github库 SystemAudioCaptureAndroid&#xff0c;实现了在安卓手机上录制系统播放声音的功能&#xff0c;也就是说&#xff0c;只要一个安卓应用没有设置不允许其它应用录制声音&#xff0c;该插件可以录制该应用播放的声音。…

Mac中安装OhMyZsh

Mac中安装OhMyZsh 文章目录 Mac中安装OhMyZsh一、Homebrew二、OhMyZsh1、Oh-My-Zsh配置1.1&#xff1a;主题配置1.2&#xff1a;插件配置&#xff08;语法高亮和自动提示&#xff09;1、zsh-autosuggestions&#xff08;需下载安装&#xff09;&#xff1a;高亮显示所有支持的命…

生信:TCGA学习(R、RStudio安装与下载、常用语法与常用快捷键)

前置环境 macOS系统&#xff0c;已安装homebrew且会相关命令。 近期在整理草稿区&#xff0c;所以放出该贴。 R语言、RStudio、R包安装 R语言安装 brew install rRStudio安装 官网地址&#xff1a;https://posit.co/download/rstudio-desktop/ R包下载 注意R语言环境自带…

elementUI input 禁止内容两端存在空格,或者是自动去除两端空格

需求 项目中有需求&#xff1a;输入框中禁止内容两端存在空格&#xff0c;或者是自动去除两端空格。 解决方法 vue的api文档中有过介绍&#xff0c;使用.trim可以去掉用户输入内容中两端的空格&#xff0c;如下图 代码 <el-input v-model.trim"name" cleara…

flink同步mysql数据表到pg库

1.关闭防火墙和selinux systemctl stop firewalld systemctl disable firewalld systemctl status firewalldvi /etc/selinux/config 修改为disabled2.安装java8 yum list java-1.8* yum install java-1.8.0-openjdk* -yjava -version3.下载和部署postgresql 下载地址&#…

HBase理论_HBase架构组件介绍

近来有些空闲时间&#xff0c;正好最近也在开发HBase相关内容&#xff0c;借此整理一下学习和对HBase组件的架构的记录和个人感受&#xff0c;付出了老夫不少心血啊&#xff0c;主要介绍的就是HBase的架构设计以及我的拓展内容。内容如有不当或有其他理解 matirx70163.com HB…

第九部分 :1.STM32之通信接口《精讲》(USART,I2C,SPI,CAN,USB)

本芯片使用的是STM32F103C8T6型号 STM32F103C8T6是STM32F1系列中的一种较常用的低成本ARM Cortex-M3内核MCU&#xff0c;具有丰富的通信接口&#xff0c;包括USART、SPI、I2C等。下面是该芯片上通信接口的管脚分布、每个接口的工作模式、常用应用场景和注意事项。 1. USART (通…

ODOO学习笔记(8):模块化架构的优势

灵活性与可定制性 业务流程适配&#xff1a;企业的业务流程往往因行业、规模和管理方式等因素而各不相同。Odoo的模块化架构允许企业根据自身的具体业务流程&#xff0c;选择和组合不同的模块。例如&#xff0c;一家制造企业可以启用采购、库存、生产和销售模块&#xff0c;并通…

MATLAB课程:AI工具辅助编程——MATLAB+LLMs

给出一些可能有用的方法辅助大家写代码。 方法一&#xff1a;MATLAB软件LLM (不太懂配置的同学们为了省事可以主要用这个方法) 方法一特别针对本门MATLAB教学课程&#xff0c;给出一种辅助ai工具的操作指南。MATLAB中可以安装MatGPT插件&#xff0c;该插件通过调用ChatGPT的API…

C++二叉平衡搜索树:AVL树的插入、删除与平衡

目录 引言 AVL树的概念 AVL树节点的定义 AVL树的插入 AVL树的基本结构 AVL树的插入 第一步&#xff1a;按搜索树的规则进行插入 第二步&#xff1a;更新平衡因子 1、父节点的平衡因子为 parent->bf 0 2、更新完 parent 的 bf&#xff0c;如果 parent->bf 1…

机器学习(1)

一、机器学习 机器学习&#xff08;Machine Learning, ML&#xff09;是人工智能&#xff08;Artificial Intelligence, AI&#xff09;的一个分支&#xff0c;它致力于开发能够从数据中学习并改进性能的算法和模型。机器学习的核心思想是通过数据和经验自动优化算法&#xff…

【Kafka】集成案例:与Spark大数据组件的协同应用

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《大数据前沿&#xff1a;技术与应用并进》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是kafka 2、Kafka 的主要特性 3、Kafka 的…