uniapp 缓存请求文件时 判断是否有文件缓存 并下载和使用

fileCache.js

复制代码
// ========== 核心Promise函数 ==========

/**
 * 获取文件系统 (Promise封装)
 * @param {number} fsType - 文件系统类型,如 plus.io.PRIVATE_DOC
 * @returns {Promise<FileSystem>}
 */
function getFileSystem(fsType) {
	return new Promise((resolve, reject) => {
		plus.io.requestFileSystem(fsType, resolve, reject);
	});
}

/**
 * 确保目录存在,不存在则创建 (Promise封装)
 * @param {DirectoryEntry} root - 根目录Entry
 * @param {string} dirPath - 目录路径
 * @returns {Promise<DirectoryEntry>}
 */
function ensureDirectory(root, dirPath) {
	return new Promise((resolve, reject) => {
		root.getDirectory(dirPath, {
			create: false
		}, resolve, (error) => {
			console.log('dirPath', dirPath, error);
			if (error.code === 14) {
				console.log('dirPathOk', dirPath);
				root.getDirectory(dirPath, {
					create: true
				}, resolve, reject);
			} else {
				console.log('dirPathFF', dirPath);
				reject(new Error(`获取目录失败: ${error.message}`));
			}
		});
	});
}

/**
 * 检查文件是否存在并获取可用URL (Promise封装)
 * @param {string} filePath - 文件路径(如 "_doc/images/avatar.png")
 * @returns {Promise<{url: string, entry: FileEntry}>}
 */
function checkAndGetFileUrl(filePath) {
	return new Promise((resolve, reject) => {
		plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
			const platformPath = plus.io.convertLocalFileSystemURL(entry.toURL());
			resolve({
				url: platformPath,
				entry
			});
		}, (error) => {
			reject(new Error(`文件不存在或无法访问: ${filePath} - ${error.message}`));
		});
	});
}

// 综合示例:下载文件到PRIVATE_DOC指定路径(Promise模式)
async function downloadFileToPrivateDoc(downloadUrl, saveFileName) {
	return new Promise((resolve, reject) => {
		// 1. 合成目标路径:_doc/downloads/ + 你指定的文件名
		const targetPath = `${saveFileName}`;

		// 2. 创建下载任务[citation:7]
		const downloadTask = plus.downloader.createDownload(
			downloadUrl, {
			filename: targetPath, // 关键:指定保存路径和文件名
			timeout: 120000 // 可选:设置超时时间(毫秒)
		},
			(download, status) => {
				// 3. 下载完成回调
				if (status === 200) {
					console.log('文件下载成功,临时保存于:', download.filename);

					// 4. 获取可用于img标签的file://路径[citation:6]
					const finalPath = plus.io.convertLocalFileSystemURL(download.filename);
					console.log('最终可用路径:', finalPath);

					resolve({
						fileEntry: download,
						savedPath: download.filename, // 如 _doc/downloads/myImage.jpg
						usableLocalUrl: finalPath // 如 file:///storage/emulated/0/Android/data/.../myImage.jpg
					});
				} else {
					reject(new Error(`下载失败,状态码: ${status}`));
				}
			}
		);

		// 5. 可选:监听下载进度[citation:1][citation:10]
		downloadTask.addEventListener('statechanged', (task, status) => {
			if (task.state === 3) { // 下载中
				const progress = task.totalSize > 0 ?
					Math.round((task.downloadedSize / task.totalSize) * 100) :
					0;
				console.log(`下载进度: ${progress}%`);
				// 这里可以更新UI进度条
			}
		});

		// 6. 开始下载任务[citation:7]
		downloadTask.start();
	});
}


function getFileNameFromUrl(url) {
	try {
		// 创建URL对象,自动处理完整URL
		const urlObj = new URL(url);
		// 获取路径部分,然后取最后一段
		const fileName = urlObj.pathname.split('/').pop();
		return fileName || ''; // 返回文件名,为空则返回空字符串
	} catch (e) {
		// 如果不是合法完整URL,尝试直接处理
		return url.split('/').pop().split('?')[0].split('#')[0];
	}
}

// ========== 综合使用示例 ==========
/* export async function handleFileOperations(dir,fileUrl) {
	try {
		// 1. 获取文件系统
		const fs = await getFileSystem(plus.io.PRIVATE_DOC);
		console.log('文件系统获取成功');

		// 2. 确保下载目录存在
		const downloadsDir = await ensureDirectory(fs.root, 'fileCache');
		console.log('目录已就绪:', downloadsDir.fullPath);

		// 3. 定义文件路径和远程URL
		//const remoteUrl = 'https://example.com/path/to/image.jpg';
		
		var fileName = getFileNameFromUrl(fileUrl);
		
		const targetFilePath = '_doc/fileCache/'+dir+"/"+fileName;
	    

		// 4. 检查文件是否已存在
		try {
			const { url: existingUrl } = await checkAndGetFileUrl(targetFilePath);
			// 更新图片显示
			// this.previewUrl = existingUrl;
			// existingUrl = `'${existingUrl}'`
			console.log('文件已存在,直接使用:', existingUrl);
			console.log(typeof existingUrl);
			return existingUrl;
		} catch (notExistError) {
			console.log('文件不存在,开始下载...');
		    
			// 5. 下载文件
			const fileEntry = await downloadFileToPrivateDoc(fileUrl, targetFilePath);
			console.log('文件下载完成:', fileEntry);

			// 6. 获取可用URL
			const { url: newUrl } = await checkAndGetFileUrl(targetFilePath);
			console.log('文件可用路径:', newUrl);
			// 更新图片显示
			// this.previewUrl = newUrl;
			return newUrl;
		}
	} catch (error) {
		console.error('操作失败:', error.message);
		throw error;
	}
} */



export function handleFileOperations(dir, fileUrl) {
	return new Promise((resolve, reject) => {
		// #ifdef WEB
		resolve(fileUrl);
		// #endif
		// #ifdef APP-PLUS
		getFileSystem(plus.io.PRIVATE_DOC)
			.then(fs => ensureDirectory(fs.root, 'fileCache'))
			.then(() => {
				const fileName = getFileNameFromUrl(fileUrl);
				const targetFilePath = '_doc/fileCache/' + dir + "/" + fileName;

				return checkAndGetFileUrl(targetFilePath)
					.then(({ url }) => {
						console.log('文件已存在,直接使用');
						resolve(url);
					})
					.catch(() => {
						console.log('文件不存在,开始下载');
						return downloadFileToPrivateDoc(fileUrl, targetFilePath)
							.then(() => checkAndGetFileUrl(targetFilePath))
							.then(({ url }) => {
								console.log('文件下载完成');
								resolve(url);
							});
					});
			})
			.catch(error => {
				console.error('操作失败:', error.message);
				reject(error);
			});
		// #endif
	});
}

调用 handleFileOperations 方法,传入本地缓存子目录,和问价url,会自动判断是否有缓存,有直接返回缓存本地路径,无则下载,并返回本地文件路径

main.js

复制代码
import { handleFileOperations } from '@/utils/fileCache.js';
Vue.prototype.$handleFileOperations = handleFileOperations;

使用示例

image-src.vue

复制代码
<template>
  <view>
    <image mode="aspectFill" :style="'width: '+ width +'; height: '+ height +';border-radius: ' + borderRadius + ';'" v-if="url && !error" :src="url" />
    <view v-if="loading">加载中...</view>
    <image v-if="error" :style="'width: '+ width +'; height: '+ height +';border-radius: ' + borderRadius + ';'" :src="errorImage" />
  </view>
</template>

<script>
export default {
  props: ['promiseFunc','interfacePath','width','height','borderRadius','errorImage'],
  data() {
    return { url: '', loading: true, error: false };
  },
  async mounted() {
    this.url = await this.$handleFileOperations(this.interfacePath,this.promiseFunc);
    // console.log('this.url',this.url);
	this.loading = false;
  }
}
</script>

使用 $handleFileOperations 可自动使用和下载缓存,并返回本地路径

相关推荐
崔庆才丨静觅15 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
陌上丨16 小时前
Redis的Key和Value的设计原则有哪些?
数据库·redis·缓存
passerby606116 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了16 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅16 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅16 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅17 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment17 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅17 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊17 小时前
jwt介绍
前端