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/...

相关推荐
郝学胜-神的一滴7 分钟前
Cesium绘制线:从基础到高级技巧
前端·javascript·程序人生·线性代数·算法·矩阵·图形渲染
蒙奇D索大39 分钟前
【计算机网络】408计算机网络高分指南:物理层编码与调制技术精讲
java·前端·学习·计算机网络
无盐海1 小时前
CSRF漏洞攻击(跨站请求伪造攻击)
前端·csrf
慧一居士1 小时前
CSS3 全部功能点介绍,使用场景,对应功能点完整使用示例
前端
烛阴1 小时前
深入Lua包(Package)与依赖管理
前端·lua
IT_陈寒1 小时前
5个Vue3性能优化技巧,让你的应用提速50% 🚀(附实测对比)
前端·人工智能·后端
god001 小时前
chromium项目中添加源文件(BUILD.gn项目中添加源文件)
java·服务器·前端
快乐非自愿1 小时前
Vue 缓存之坑,变量赋值方式和响应式数据
前端·vue.js·缓存
Github掘金计划1 小时前
别再用 “臃肿监控” 了!这款轻量监控神器开源 3 月狂揽 1.3k Star!
前端·监控
努力学习的少女2 小时前
SpaekSql函数
前端·数据库