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

相关推荐
ZL不懂前端几秒前
微前端介绍
前端
Lear1 分钟前
uniapp&微信小程序markdown&latex
前端
江城开朗的豌豆1 分钟前
CSS篇:CSS选择器详解与权重计算全指南
前端·css·面试
asing2 分钟前
之家中后台前端解决方案 - 支点2.0
前端·javascript
Aphasia3119 分钟前
一家前端远程实习公司的笔试题分享📑
前端·面试
无名之逆10 分钟前
Hyperlane 文件分块上传服务端
服务器·开发语言·前端·网络·http·rust·php
海风极客28 分钟前
一文搞懂JSON和HJSON
前端·后端·面试
阳树阳树38 分钟前
Solidjs 响应式 & 编译原理初探
前端·javascript·面试
liangmou212142 分钟前
HTML5的笔记
前端·笔记·html·html5
MurphyChen1 小时前
前端请求进化史 :从 Form 到 Server Actions 🚀
前端·javascript·面试