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 可自动使用和下载缓存,并返回本地路径

相关推荐
进击的野人1 小时前
Vue中key的作用与Diff算法原理深度解析
前端·vue.js·面试
打工仔张某2 小时前
React Fiber 原理与实践 Demo
前端
chalmers_152 小时前
require 根据工程目录的相对路径-require新文件实现简单的热更新
linux·前端·javascript
Cache技术分享2 小时前
264. Java 集合 - 插入元素性能对比:LinkedList vs ArrayList
前端·后端
周不凢2 小时前
摄像头云台控制(摄像头操作)
前端·vue.js
i_am_a_div_日积月累_2 小时前
css排除样式:not:has
前端·css
跟着珅聪学java2 小时前
Jedis SetParams教程:参数化设置 Redis 键值对
数据库·redis·缓存
Mapmost2 小时前
【高斯泼溅】告别近看模糊!Mapmost如何重塑场景细节
前端
qiyue772 小时前
裁员这么猛,AI修仙抗一波
前端·人工智能·ai编程