You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust WASM中选择文件并获取字节、文本或Blob ObjectURL?

实现按钮触发文件上传并获取文件内容/Blob URL

核心思路

通过隐藏的<input type="file">元素,用可见按钮触发其点击事件,监听input的change事件处理选中文件,再借助web_sys或gloo完成文件内容读取或Blob URL生成。


一、基础DOM结构

先在页面中添加隐藏的文件输入框和触发按钮:

<!-- 隐藏的文件输入框 -->
<input type="file" id="file-input" style="display: none;">
<!-- 可见的触发按钮 -->
<button id="upload-btn">选择文件上传</button>

二、用web_sys实现

步骤1:绑定按钮点击事件,触发文件选择

use web_sys::{HtmlInputElement, HtmlButtonElement, Event};
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::spawn_local;

// 获取DOM元素
let file_input = document().get_element_by_id("file-input")
    .unwrap()
    .dyn_into::<HtmlInputElement>()
    .unwrap();
let upload_btn = document().get_element_by_id("upload-btn")
    .unwrap()
    .dyn_into::<HtmlButtonElement>()
    .unwrap();

// 按钮点击时触发文件输入框的点击
upload_btn.add_event_listener_with_callback("click", &Closure::wrap(Box::new(move |_e: Event| {
    file_input.click();
})).into_js_value()).unwrap();

步骤2:监听文件选择事件,处理文件内容

获取Blob ObjectURL

// 监听文件输入框的change事件
file_input.add_event_listener_with_callback("change", &Closure::wrap(Box::new(move |_e: Event| {
    // 获取选中的第一个文件
    if let Some(file) = file_input.files().and_then(|files| files.get(0)) {
        // 生成Blob ObjectURL
        let object_url = web_sys::Url::create_object_url_with_blob(&file).unwrap();
        // 这里可以使用object_url,比如赋值给img的src或者用于下载
        println!("Blob ObjectURL: {}", object_url);
        
        // 注意:使用完后记得释放URL,避免内存泄漏
        // web_sys::Url::revoke_object_url(&object_url).unwrap();
    }
})).into_js_value()).unwrap();

读取文件内容为Vec

file_input.add_event_listener_with_callback("change", &Closure::wrap(Box::new(move |_e: Event| {
    if let Some(file) = file_input.files().and_then(|files| files.get(0)) {
        spawn_local(async move {
            // 将文件转换为ArrayBuffer
            let array_buffer = file.array_buffer().await.unwrap();
            // 转换为Vec<u8>
            let bytes = js_sys::Uint8Array::new(&array_buffer).to_vec();
            println!("文件字节数: {}", bytes.len());
            
            // 如果需要字符串内容(假设是UTF-8编码)
            let content = String::from_utf8_lossy(&bytes);
            println!("文件内容: {}", content);
        });
    }
})).into_js_value()).unwrap();

三、用gloo实现(更简洁)

gloo提供了更易用的封装,比如gloo_utils处理DOM事件,gloo_file处理文件读取。

步骤1:添加依赖

在Cargo.toml中添加:

[dependencies]
gloo-utils = "0.2"
gloo-file = "0.2"
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["HtmlInputElement", "HtmlButtonElement", "Url"] }

步骤2:实现代码

use gloo_utils::document;
use gloo_file::File;
use web_sys::{HtmlInputElement, HtmlButtonElement};
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::spawn_local;

// 获取DOM元素
let file_input = document().get_element_by_id("file-input")
    .unwrap()
    .dyn_into::<HtmlInputElement>()
    .unwrap();
let upload_btn = document().get_element_by_id("upload-btn")
    .unwrap()
    .dyn_into::<HtmlButtonElement>()
    .unwrap();

// 按钮触发文件选择
upload_btn.add_event_listener("click", move |_| {
    file_input.click();
}).unwrap();

// 处理文件选择
file_input.add_event_listener("change", move |_| {
    let files = file_input.files().unwrap();
    if files.length() == 0 {
        return;
    }
    let file = File::from(files.get(0).unwrap());
    
    // 生成Blob ObjectURL
    let object_url = web_sys::Url::create_object_url_with_blob(&file).unwrap();
    println!("Blob ObjectURL: {}", object_url);
    
    // 读取文件内容为Vec<u8>
    spawn_local(async move {
        let bytes = file.read_bytes().await.unwrap();
        println!("文件字节数: {}", bytes.len());
        
        let content = String::from_utf8_lossy(&bytes);
        println!("文件内容: {}", content);
    });
}).unwrap();

注意事项

  • 生成的Blob ObjectURL在不需要使用时,一定要调用web_sys::Url::revoke_object_url(&object_url)释放,避免浏览器内存泄漏。
  • 如果需要支持多选文件,给<input>添加multiple属性即可,然后遍历files对象处理每个文件。

内容的提问来源于stack exchange,提问作者Durfsurn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 07:50:19