参考HTML5联盟
IO模块管理本地文件系统,用于对文件系统的目录浏览、文件的读取、文件的写入等操作。通过plus.io可获取文件系统管理对象。
深入uniapp:封装IO模块常用功能以高效管理本地文件系统
在移动应用开发过程中,对本地文件系统的操作是非常常见的需求。uniapp
作为一个使用 Vue.js 开发所有前端应用的框架,可以编译到iOS、Android、H5以及各种小程序等多个平台,其内置的IO模块提供了丰富的API来满足开发者对本地文件系统的操作需求。
本文将详细介绍如何在 uniapp
中封装IO模块的常用功能,以便更高效、更便捷地管理本地文件系统。
1. 了解uniapp的IO模块
uniapp
的IO模块主要提供了文件的读取、写入、删除、复制、移动等操作。在开始封装之前,我们需要先了解这些API的基本用法。
1.1 文件的读取
使用 uni.readFile
方法可以读取本地文件的内容。这是一个异步操作,需要在回调函数中处理读取到的数据。
uni.readFile({ filePath: 'path/to/file', // 文件的路径 success: (res) => { console.log(res.data); // 读取到的文件内容 }, fail: (err) => { console.error(err); } });
1.2 文件的写入
uni.writeFile
方法用于写入文件。如果文件不存在,则会创建新文件。
uni.writeFile({ filePath: 'path/to/file', data: 'some data to write', success: () => { console.log('File written successfully'); }, fail: (err) => { console.error(err); } });
1.3 文件的删除
使用 uni.removeFile
方法可以删除本地文件。
uni.removeFile({ filePath: 'path/to/file', success: () => { console.log('File removed successfully'); }, fail: (err) => { console.error(err); } });
1.4 文件的复制和移动
uni.copyFile
和 uni.moveFile
方法分别用于复制和移动文件。
// 复制文件 uni.copyFile({ srcPath: 'path/to/src/file', destPath: 'path/to/dest/file', success: () => { console.log('File copied successfully'); }, fail: (err) => { console.error(err); } }); // 移动文件 uni.moveFile({ srcPath: 'path/to/src/file', destPath: 'path/to/dest/file', success: () => { console.log('File moved successfully'); }, fail: (err) => { console.error(err); } });
2. 封装常用功能
了解了IO模块的基本用法后,我们可以开始封装一些常用的功能,以便在项目中重复使用。
2.1 创建一个文件管理工具类
首先,我们可以创建一个文件管理工具类,将所有的文件操作都封装在这个类中。
class FileManager { constructor() { // 初始化代码(如果有的话) } // 在这里添加文件操作的方法 } export default new FileManager();
2.2 封装读取文件的方法
我们可以在 FileManager
类中添加一个 readFile
方法来封装文件的读取操作。
class FileManager { // ... readFile(filePath, successCallback, failCallback) { uni.readFile({ filePath: filePath, encoding: 'utf8', // 指定读取文件的字符编码 success: (res) => { if (typeof successCallback === 'function') { successCallback(res.data); } }, fail: (err) => { if (typeof failCallback === 'function') { failCallback(err); } } }); } // ... }
2.3 封装写入文件的方法
同样地,我们可以在类中添加一个 writeFile
方法来封装文件的写入操作。
class FileManager { // ... writeFile(filePath, data, successCallback, failCallback) { uni.writeFile({ filePath: filePath, data: data, encoding: 'utf8', // 指定写入文件的字符编码 success: () => { if (typeof successCallback === 'function') { successCallback(); } }, fail: (err) => { if (typeof failCallback === 'function') { failCallback(err); } } }); } // ... }
2.4 封装删除、复制和移动文件的方法
用类似的方式,我们可以封装删除、复制和移动文件的方法。
class FileManager { // ... removeFile(filePath, successCallback, failCallback) { uni.removeFile({ filePath: filePath, success: () => { if (typeof successCallback === 'function') { successCallback(); } }, fail: (err) => { if (typeof failCallback === 'function') { failCallback(err); } } }); } copyFile(srcPath, destPath, successCallback, failCallback) { uni.copyFile({ srcPath: srcPath, destPath: destPath, success: () => { if (typeof successCallback === 'function') { successCallback(); } }, fail: (err) => { if (typeof failCallback === 'function') { failCallback(err); } } }); } moveFile(srcPath, destPath, successCallback, failCallback) { uni.moveFile({ srcPath: srcPath, destPath: destPath, success: () => { if (typeof successCallback === 'function') { successCallback(); } }, fail: (err) => { if (typeof failCallback === 'function') { failCallback(err); } } }); } // ... }
3. 使用封装后的文件管理工具
封装完成后,我们就可以在项目中使用这个文件管理工具了。
import FileManager from './FileManager'; // 读取文件 FileManager.readFile('path/to/file', (data) => { console.log(data); }, (err) => { console.error(err); }); // 写入文件 FileManager.writeFile('path/to/file', 'some data', () => { console.log('File written successfully'); }, (err) => { console.error(err); }); // 删除文件 FileManager.removeFile('path/to/file', () => { console.log('File removed successfully'); }, (err) => { console.error(err); }); // 复制文件 FileManager.copyFile('path/to/src/file', 'path/to/dest/file', () => { console.log('File copied successfully'); }, (err) => { console.error(err); }); // 移动文件 FileManager.moveFile('path/to/src/file', 'path/to/dest/file', () => { console.log('File moved successfully'); }, (err) => { console.error(err); });
4. 总结
通过封装 uniapp
的IO模块,我们可以更方便、更高效地管理本地文件系统。封装后的文件管理工具类具有良好的可复用性和可扩展性,可以根据项目的实际需求进行进一步的定制和优化。下面是async-await风格的封装:
/** * 储存文件到指定的地址:把一个文件移动到另外一个位置 剪切文件 重命名文件 * @param {String} url 新的地址 _doc/ 开头 * @param {String} file 原文件地址 * @param {String} newfilename 新的文件名 */ async function saveFile(url, file, newfilename) { let c = await creatDirs(url) let isokm = moveDirectyOrFile(file, url + "/", newfilename); return isokm } //循环创建目录 url:"_doc/...." _doc开头 async function creatDirs(url) { let urllist = url.split("/"); console.log(urllist) //创建文件夹 let u = ""; for (let i = 0; i < urllist.length - 1; i++) { let j = i; if (i == 0) { u = urllist[i]; } else { u = u + "/" + urllist[i]; } console.log(i + "-------------------") console.log(u) console.log(urllist[j + 1]) await CreateNewDir(u, urllist[j + 1]); } } //重命名目录或文件名 function moveDirectyOrFile(srcUrl, dstUrl, newName) { //srcUrl需要移动的目录或文件,dstUrl要移动到的目标目录(父级) plus.io.resolveLocalFileSystemURL(srcUrl, function(srcEntry) { //console.log(111) plus.io.resolveLocalFileSystemURL(dstUrl, function(dstEntry) { //console.log(222) if (srcEntry.isDirectory) { //console.log(33) srcEntry.moveTo(dstEntry, newName, function(entry) { //console.log("New Path: " + entry.fullPath); return true; }, function(e) { return e; //console.log(e.message); }); } else { srcEntry.moveTo(dstEntry, newName, function(entry) { //console.log("New Path: " + entry.fullPath); return true; }, function(e) { return e; //console.log(e.message); }); } }, function(e) { uni.showToast({ title: '获取目标目录失败:' + e.message, duration: 2000, icon: 'none' }); }); }, function(e) { uni.showToast({ title: '获取目录失败:' + e.message, duration: 2000, icon: 'none' }); }); } //创建一个新目录 function CreateNewDir(url, dirName) { //url值可支持相对路径URL、本地路径URL return new Promise((resolver, reject) => { plus.io.resolveLocalFileSystemURL(url, function(entry) { entry.getDirectory(dirName, { create: true, exclusive: false }, function(dir) { resolver(true) }, function(error) { reject(error.message) uni.showToast({ title: dirName + '目录创建失败:' + error.message, duration: 2000, icon: 'none' }); }); }, function(e) { reject(error.message) uni.showToast({ title: '获取目录失败:' + e.message, duration: 2000, icon: 'none' }); }); }) } /** * 获取文件数据 * @param {String} url 文件路径,最好是相对路径 url:"_doc/...." _doc开头 */ function getFileContext(url) { return new Promise((resolve, reject) => { plus.io.resolveLocalFileSystemURL(url, (entry) => { if (entry.isFile) { entry.file(function(file) { console.log(file); const fileReader = new plus.io.FileReader(); console.log("getFile:" + JSON.stringify(file)); fileReader.onload = function(evt) { console.log(evt); resolve(evt.target) } fileReader.readAsText(file, 'utf-8'); }); } else { reject('错误:路径必须是文件') uni.showModal({ title: "错误", content: "路径必须是文件" }) } }, (e) => { reject(e) uni.showModal({ title: "错误", content: "打开文件系统时出错" }) }); }) } /** * 复制文件 * @param {String} url 文件地址,文件路径,最好是相对路径 url:"_doc/...." _doc开头 * @param {String} newUrl 目标目录,最好是相对路径 url:"_doc/...." _doc开头 * @param {String} newName 拷贝后的文件名称,默认为原始文件名称 */ function copyFileTo(url, newUrl, newName) { let len = arguments.length; return new Promise((resolve, reject) => { plus.io.resolveLocalFileSystemURL(url, async (entry) => { if (entry.isFile) { let c = await creatDirs(newUrl) let u = await getDirsys(newUrl) if (len == 3) { entry.copyTo(u, newName, en => { console.log(en); resolve(en) }, e => { console.log(e); reject('错误:复制时出现错误') uni.showModal({ title: "错误", content: "复制时出现错误" }) }) } else { entry.copyTo(u, "", en => { console.log(en); resolve(en) }, e => { console.log(JSON.stringify(e)); reject('错误:复制时出现错误') uni.showModal({ title: "错误", content: "复制时出现错误" }) }) } } else { reject('错误:路径必须是文件') uni.showModal({ title: "错误", content: "路径必须是文件" }) } }, (e) => { console.log(e); reject(e) uni.showModal({ title: "错误", content: "打开文件系统时出错" }) }); }) } /** * 根据条件,获取目录中包含的文件及子目录 * @param {Object} params { url:指定的目录, * type:要列出的是文件file,还是目录dir,还是所有all, * regex:正则表达式,根据文件或者目录的名称进行筛选 * } * @return {Promise} 返回 列表Array */ async function getDirList(params) { let url = params.url ?? "_doc" let type = params.type ?? "all" let regex = params.regex ?? new RegExp("") const d = await getDirsys(url) return new Promise((resolve, reject) => { d.createReader().readEntries(entries => { let result = [] for (let i = 0; i < entries.length; i++) { let a = { url: entries[i].fullPath, name: entries[i].name } switch (params?.type) { case "file": { if (entries[i].isFile == true && regex.test(entries[i].name)) { result.push(a) } break; } case "dir": { if (entries[i].isDirectory == true && regex.test(entries[i].name)) { result.push(a) } break; } case "all": { if (regex.test(entries[i].name)) { result.push(a) } break; } default: { if (regex.test(entries[i].name)) { result.push(a) } break; } } } // let ul = entries.filter(e=>e.isFile == true) // let result = ul.map(e=>{ // return { // url:e.fullPath, // name:e.name // } // }) resolve(result) }, e => { reject(e) uni.showModal({ title: "错误", content: "Read entries failed: " + e.message }) }) }) } //删除目录或者文件,如果是目录,将会删除其下的所有文件及子目录 async function remove(url) { const d = await getDirsys(url) return new Promise((resolve, reject) => { if (d.isDirectory) { //删除目录将会删除其下的所有文件及子目录 不能删除根目录,如果操作删除根目录将会删除目录下的文件及子目录,不会删除根目录自身 d.removeRecursively(() => { resolve("删除成功") }, e => { console.log(e); uni.showModal({ title: "删除时错误", content: e.message }) }) } if (d.isFile) { d.remove(() => { resolve("删除成功") }, e => { console.log(e); uni.showModal({ title: "删除时错误", content: e.message }) }) } }) } /** * 写数据 * @param {Object} url 创建文件的路径,必须是已经存在的路径 * @param {Object} filename 文件名 */ function writeFile(url,filename,str) { return new Promise((resolve,reject)=>{ plus.io.requestFileSystem(url, function(fs) { // 可通过fs进行文件操作 console.log("Request file system success!"); console.log(fs.name); fs.root.getFile( filename, { create: true, exclusive: false }, fileEntry => { fileEntry.createWriter( writer => { writer.onwrite = e => { console.log(e.target.fileName); resolve(e) // setTimeout(function() { // // that.proshow = false; // uni.openDocument({ // filePath: `file://${e.target.fileName}`, //这里必须加file://否则会报错打不开文件 // success: function(res) { // console.log(res); // resolve(res) // }, // fail(res) { // console.log(res); // reject(res) // } // }); // }, 1000); }; writer.write(str); }, function(e) { uni.showToast({ title: '导出文件失败,请检查你的权限', icon: 'none' }); reject(e) } ); }, e => { console.log(e); reject(e) } ); }, function(e) { reject(e) }); }) } //获取目录对象 function getDirsys(url) { return new Promise((resolve, reject) => { plus.io.resolveLocalFileSystemURL(url, (entry) => { resolve(entry) }, (e) => { reject(e) console.log(e); }); }) } export default { saveFile, creatDirs, moveDirectyOrFile, getFileContext, copyFileTo, getDirList, getDirsys, writeFile, remove }