uniapp中IO模块(管理本地文件系统)的常用功能封装

简介: uniapp中IO模块(管理本地文件系统)的常用功能封装

参考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.copyFileuni.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
}

相关文章
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的学生签到系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的学生签到系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的疫情期间学生请假与销假系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的疫情期间学生请假与销假系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的校园保修系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的校园保修系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的外卖点外卖系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的外卖点外卖系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的医院挂号预约系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的医院挂号预约系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的点餐系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的点餐系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的研学自习室选座与门禁系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的研学自习室选座与门禁系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的疫苗预约系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的疫苗预约系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的考研资料分享系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的考研资料分享系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的投票评选系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的投票评选系统的详细设计和实现(源码+lw+部署文档+讲解等)