WASM与OPFS组合技系列一(文件导入)

简介

wasm(WebAssembly)和OPFS(Origin Private File System)是前端在进行科学计算和大文件处理时常用的技术,本系列就着重介绍怎么将两种技术组合来实现大文件计算的同时保持高效率和低内存效果。

OPFS介绍

OPFS 全称为 Origin-Private File System (源私有文件系统),是浏览器提供的一种新型 Web API,允许网页在用户设备上创建和管理一个私有的、与网站源(Origin)绑定的虚拟文件系统 。它是现代浏览器支持的标准技术,旨在解决 Web 应用对文件高效读写的需求(尤其是大文件和二进制数据)。

通过Can I Use可以看到,目前除了IE,其他主流浏览器都已支持该特性,可以放心使用。

OPFS本身对于文件读写支持同步和异步两种模式,主线中使用时只可以使用异步,WebWorker中两种模式都可以正常使用。

文件导入示例

本期着重介绍怎么将用户文件写入到OPFS中。

1、获取文件对象

通过简单的<input type="file" />控件可以获取到文件对象。

2、将文件对象发送到独立线程中

js 复制代码
const uploadFile = () => {
    const uploadFile = document.getElementById("file").files[0];
    if (!uploadFile) {
      alert("请选择需要上传的文件");
      return;
    }
    worker.postMessage({
      type: "copy",
      file: uploadFile,
    });
};

3、在线程中将文件切片保存到OPFS中

js 复制代码
const copyFileToOPFS = async (file) => {
  Module.print("准备上传文件:", file.name);
  // 线程中可以直接使用同步文件读取
  const fileReader = new FileReaderSync();
  const filename = file.name;
  // 获取OPFS根目录
  const root = await navigator.storage.getDirectory();
  // 获取文件句柄
  const fileHandle = await root.getFileHandle(filename, {
    create: true, // 如果没有文件则创建一个新文件
  });
  // 获取文件同步写句柄,只可以在worker中使用
  const accessHandle = await fileHandle.createSyncAccessHandle();
  let times = 0;
  let index = 0;
  const length = 1024 * 1024 * 50;
  let flag = true;
  const fileSize = file.size;
  while (flag) {
    times++;
    if (times > 1000) {
      flag = false;
      break;
    }
    if (index >= fileSize) {
      flag = false;
      break;
    }
    const start = index;
    let end = index + length;
    if (end > fileSize) {
      end = fileSize;
    }
    // 获取文件切片
    const content = file.slice(start, end);
    // 读取为ArrayBuffer
    let arrayBuffer = fileReader.readAsArrayBuffer(content);
    // 将数据写入文件
    accessHandle.write(arrayBuffer, {
      at: start, // 文件内字节下标,主要用于分片写入文件
    });
    // 将数据刷入文件中,只有执行了flush数据才会真实保存到文件中
    accessHandle.flush();
    arrayBuffer = null;
    index = end;
    Module.print("文件已上传:", ((index / fileSize) * 100).toFixed(2), "%");
  }
  // 此处必须关闭文件句柄,不然会导致后续无法再次获取句柄
  accessHandle.close();
  Module.print("文件上传成功: " + file.name);
};

源码示例

github.com/yangyanggu/...

相关推荐
晓13137 小时前
React篇——第三章 状态管理之 Redux 篇
前端·javascript·react.js
子兮曰7 小时前
🚀24k Star 的 Pretext 为何突然爆火:它不是排版库,而是在重写 Web 文本测量
前端·javascript·github
@大迁世界7 小时前
11.在 React.js 中,state 与 props 的差异体现在哪里?
前端·javascript·react.js·前端框架·ecmascript
Giant1007 小时前
🔥前端跨域封神解法:Vite Proxy + Express CORS,一篇搞定所有跨域坑!
前端·javascript·面试
用户3167361303427 小时前
SSE消息推送前后端代码
前端·后端
像我这样帅的人丶你还7 小时前
JavaScript 迭代器详解
前端·javascript
逍遥归来7 小时前
《SWIFTER -Swift开发者必备Tips》学习笔记
前端
timi先生7 小时前
语料库全栈项目部署 (Vue + Java + CQPweb)
java·前端·vue.js
Lazy_zheng7 小时前
Map / Set / WeakMap / WeakSet,一次给你讲透
前端·javascript·面试
learyuan7 小时前
Windows原生开发
前端