Tauri?打開(kāi)本地文件踩坑分析解決
Tauri 打開(kāi)本地文件踩坑
最近我在嘗試使用Tauri,遇到一個(gè)問(wèn)題,其實(shí)從事后來(lái)看,如果熟悉Tauri的api的話,是件分分鐘就能解決的事情,但由于思維慣性,實(shí)際卻困擾了我一整天,寫(xiě)文記錄一下我踩坑的過(guò)程。
需求
需求很簡(jiǎn)單,就是打開(kāi)本地圖片進(jìn)行展示,同時(shí)還要能拿到圖片在本地的絕對(duì)路徑。
- 展示圖片
- 拿到絕對(duì)路徑
<input type="file" >存在的問(wèn)題
最先想到辦法,當(dāng)然是使用input元素,這是前端讀取本地文件的常規(guī)方案,而且我曾經(jīng)使用electron實(shí)現(xiàn)過(guò)一樣的功能,大致就是:
<input type="file" id="file-selector" />
document.getElementById("file-selector").addEventListener('change', e => {
const files = e.target.files
files.forEach(file => {
const url = URL.createObjectURL(file)
const path = file.path
})
})
但遺憾的是,Tauri的File對(duì)象并沒(méi)有實(shí)現(xiàn)path這個(gè)屬性。
出于安全考慮,瀏覽器并沒(méi)有提供File對(duì)象的絕對(duì)路徑,path是electron自己提供的:electron/file-object.md at main · electron/electron (github.com)。
隨后,盡管想了各種辦法,比如引入file-selector之類(lèi)的,但最終的結(jié)論是:input拿不到文件的絕對(duì)路徑。
Dialog打開(kāi)文件
我在心里吐槽“Tauri果然是不如electron”之后,我決定去Github上搜一下issue,不出所料,不只我一個(gè)人遇到這個(gè)問(wèn)題:
Getting a real path of file type input · Issue #87
這里面給出了一個(gè)拿到文件絕對(duì)路徑的辦法,那就是使用Dialog
首先在tauri.conf.json添加配置:
"allowlist": {
"dialog": {
"all": false,
"open": true
}
}
然后
import { open } from "@tauri/api/dialog"
async handler(){
let file = await open()
}
open方法會(huì)像input file一樣打開(kāi)一個(gè)文件選擇框,返回文件的絕對(duì)路徑。
如果想一次選擇多個(gè)文件,可以添加選項(xiàng):
let files = await open({ multiple: true })
實(shí)際嘗試發(fā)現(xiàn),這樣確實(shí)能拿到文件的絕對(duì)路徑,但也只有絕對(duì)路徑。
于是我就陷入了困境:通過(guò)input可以展示圖片,但拿不到絕對(duì)路徑,而dialog可以拿到絕對(duì)路徑,卻無(wú)法顯示圖片,因?yàn)榍岸藷o(wú)法直接通過(guò)一個(gè)本地的絕對(duì)路徑來(lái)展示圖片。
怎么辦呢?
fs讀取文件
于是,我開(kāi)始考慮使用Tauri提供的fs API,利用絕對(duì)路徑來(lái)讀取文件內(nèi)容,然后再轉(zhuǎn)換成Blob對(duì)象。
配置tauri.conf.json
"allowlist": {
"dialog": {
"all": false,
"open": true
},
"fs": {
"all": false,
"readFile": true,
}
}
讀取文件并轉(zhuǎn)換:
import { readBinaryFile } from '@tauri-apps/api/fs';
import { open } from "@tauri/api/dialog"
async handler(){
// 打開(kāi)文件獲取絕對(duì)路徑
let files = await open({ multiple: true })
files.forEach(async filePath => {
// 讀取二進(jìn)制文件
const contents = await readBinaryFile(filePath)
// 轉(zhuǎn)換為blob對(duì)象,然后轉(zhuǎn)換為url
const blob = new Blob([contents])
const url = URL.createObjectURL(blob)
})
}
但是,正如我預(yù)期的那樣,這么做有嚴(yán)重的性能問(wèn)題。
經(jīng)簡(jiǎn)單測(cè)試,打開(kāi)100張圖片(每張400kb左右)需要好幾秒鐘才能完成,打開(kāi)500張圖片更是花了約20秒才處理完畢。
而如果使用input file,500張圖片只要一兩秒就能搞定。
所以,雖然功能上已經(jīng)沒(méi)有問(wèn)題,但性能問(wèn)題無(wú)法忽視,看來(lái)還需要找找別的辦法。
最終解決辦法
經(jīng)過(guò)一整天的摸索,我最終找到了Tauri提供這個(gè)函數(shù):convertFileSrc,可以將一個(gè)絕對(duì)路徑轉(zhuǎn)換為類(lèi)似于URL.createObjectURL那樣的URL。
值得一提的是,這個(gè)函數(shù)和最常用的 invoke處于同一個(gè)模塊內(nèi),而且在Tauri的文檔中,convertFileSrc甚至位于invoke之前,但我卻一直沒(méi)有注意到它,一方面是因?yàn)?,之前從沒(méi)有想過(guò)要使用絕對(duì)路徑來(lái)轉(zhuǎn)換URL,因?yàn)榧兦岸耸亲霾坏竭@一點(diǎn)的;另一方面,由于思維慣性,前端打開(kāi)本地文件往往都是用的input file,遇到這個(gè)問(wèn)題我一直想的是如何從input事件著手,沒(méi)有去仔細(xì)看文檔……這就是所謂的燈下黑嗎
首先,配置tauri.conf.json
{
"allowlist": {
"dialog": {
"all": true,
"open": true
},
"protocol": {
"all": false,
"asset": true,
"assetScope": [
"$PICTURE"
]
}
},
"security": {
"csp": "default-src 'self'; img-src 'self'; asset: https://asset.localhost"
}
}
然后
import { convertFileSrc } from '@tauri-apps/api/tauri'
import { open } from "@tauri/api/dialog"
async handler(){
let files = await open({ multiple: true })
files.forEach(filePath => {
const url = convertFileSrc(filePath)
})
}
速度和HTML原生的input file差不多,雖然拿不到文件大小之類(lèi)的信息,但至少我最需要的兩個(gè)需求可以實(shí)現(xiàn)了,只要有了絕對(duì)路徑,文件大小之類(lèi)的可以交給Rust。
以上就是Tauri 打開(kāi)本地文件踩坑分析解決的詳細(xì)內(nèi)容,更多關(guān)于Tauri 打開(kāi)本地文件踩坑的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于Rust?使用?dotenv?來(lái)設(shè)置環(huán)境變量的問(wèn)題
在項(xiàng)目中,我們通常需要設(shè)置一些環(huán)境變量,用來(lái)保存一些憑證或其它數(shù)據(jù),這時(shí)我們可以使用dotenv這個(gè)crate,接下來(lái)通過(guò)本文給大家介紹Rust?使用dotenv來(lái)設(shè)置環(huán)境變量的問(wèn)題,感興趣的朋友一起看看吧2022-01-01
Rust生成隨機(jī)數(shù)的項(xiàng)目實(shí)踐
Rust標(biāo)準(zhǔn)庫(kù)中并沒(méi)有隨機(jī)數(shù)生成器,常見(jiàn)的解決方案是使用rand包,本文主要介紹了Rust生成隨機(jī)數(shù)的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
Rust?實(shí)現(xiàn)?async/await的詳細(xì)代碼
異步編程在 Rust 中的地位非常高,很多 crate 尤其是多IO操作的都使用了 async/await,這篇文章主要介紹了Rust?如何實(shí)現(xiàn)?async/await,需要的朋友可以參考下2022-09-09
使用Rust制作康威生命游戲的實(shí)現(xiàn)代碼
這篇文章主要介紹了使用Rust制作康威生命游戲,初始rust項(xiàng)目,使用wasm的項(xiàng)目模板,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09
Rust語(yǔ)言從入門(mén)到精通系列之Iterator迭代器深入詳解
這篇文章主要為大家介紹了Rust語(yǔ)言從入門(mén)到精通系列之Iterator迭代器深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Go調(diào)用Rust方法及外部函數(shù)接口前置
這篇文章主要為大家介紹了Go調(diào)用Rust方法及外部函數(shù)接口前置示例實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Rust調(diào)用函數(shù)操作符?.?和?::?的區(qū)別詳解
在Rust中,.和::操作符都可以用來(lái)調(diào)用方法,但它們的用法有所不同,所以本文就將詳細(xì)的給大家介紹一下.和::操作符的區(qū)別,感興趣的同學(xué)跟著小編一起來(lái)學(xué)習(xí)吧2023-07-07

