微信小程序 - 文件工具类 fileUtil.js
const fs = wx.getFileSystemManager();
/**
* 选择媒体附魔的ZIP
* @param {object} options
*/
function chooseMediaZip(options = {}){
const defaultOptions = { count: 9, mediaType: ['image']};
let params = {...defaultOptions, ...options};
return wx.chooseMedia(params) // 选择 *.zip.png 文件
.then(res=>{ // png 处理为 zip
return res.tempFiles.map(file => {
/* 这是附魔的bat脚本,在zip前添加了25个字节,是一个PNG文件的头:89504E470D0A1A0A0000000D49484452 转成的 base64
echo iVBORw0KGgoAAAANSUhEUg==>_________
copy /b _________ + /b %1 %~nx1.png
del /q _________
*/
// 读取zip的二进制部分
const arrayBuffer = readFileSync(file.tempFilePath, '', 26);
console.log(arrayBuffer);
// 写 zip 到目录 globalData.PATH.zippng
const zipFile = {};
zipFile.name = `${Date.now()}.zip`;
zipFile.path =`${ params.zippng }/${ zipFile.name }`;
mkdir(params.zippng); // 先创建目录
writeFileSync( zipFile.path, arrayBuffer, 'binary' ); // 写 zip 文件
return zipFile; // {name: 'fileName', path: 'http://xxx.png'}
});
}).catch(console.error);
}
/**
* 选择媒体文件
* @param {object} options
*/
function chooseMedia(options = {}){
const defaultOptions = { count: 9, mediaType: ['image']};
return wx.chooseMedia({...defaultOptions, ...options});
}
/**
* 从聊天中选择文件
* @param {number} _count
*/
function chooseFile(_count){
return wx.chooseMessageFile({ count: _count })
.then( res => {
// res 内容: {
// "errMsg":"chooseMessageFile:ok",
// "tempFiles":[
// {
// "name":"spineboy.zip",
// "size":273679,
// "time":1692946544,
// "path":"http://tmp/eZhBTvHhtCEN1328314d91c79395dce640b2f2aba2e7.zip",
// "type":"file"
// }
// ]
// }
if(res.errMsg === "chooseMessageFile:ok"){
return res.tempFiles;
}else{
return [];
}
});
}
/**
* 获取目录结构
* @param {string} rootPath
*/
function ls(rootPath) {
// 检查目录是否存在
if(!isExist(rootPath)){
return [];
}
let list = fs.statSync(`${rootPath}`, true);
if(Array.isArray(list) == false && list.isDirectory()) {
return [];
}
// 返回一个对象包含 dirPath 目录下的文件和子目录:{'file':[], 'dir': []}
return list.map(df => {
df.type = df.stats.isFile() ? 'file' : 'dir';
return df;
}).reduce((result, item) => {
item.path = `${rootPath}/${item.path}`;
result[item.type].push(item);
return result;
}, {'file':[], 'dir': []});
}
/**
* 删除文件(同步版)
* @param {string} filePath 文件路径
*/
function unlinkSync(filePath){
if(isExist(filePath) == false){
console.log(`文件不存在:${filePath}`)
return;
}
try {
const res = fs.unlinkSync(filePath);
console.log(res)
} catch(e) {
console.error(e)
}
}
/**
* 清空目录:包含所有子目录和文件
* @param {string} rootPath 要清空的目录
* @param {*} saveSelf 是否删除自己。为 false 则只清空其实的子目录和文件,但保留自己
*/
function clearDir(rootPath, saveSelf=true) {
// 检查目录是否存在
if(!isExist(rootPath)){
return;
}
// 获取:文件与子目录
let group = ls(rootPath);
if(Array.isArray(group.file) == false){ // 如果file属性不是一个数组,说明没查到东西。是个空文件夹。
return;
}
// 删除所有文件
let p = group.file.map(f => {
return new Promise((resolve, reject) => {
fs.unlink({
filePath: f.path,
success: res => resolve(res),
fail: err => reject(err)
})
});
});
// 删除全部文件后,再执行删除目录。
Promise.all(p).then(res => {
fs.rmdir({
dirPath: `${rootPath}`,
recursive: true,
success: res => console.log(res),
fail: err => console.error(err),
});
});
// 上面是直接递归删除整个目录,包括自己。这里判断一下,如果需要保留根目录,就再创建一下。
if(saveSelf){
mkdir(rootPath);
}
}
/**
* 清空目录(同步版):包含所有子目录和文件
* @param {string} rootPath 要清空的目录
* @param {*} saveSelf 是否删除自己。为 false 则只清空其实的子目录和文件,但保留自己
*/
function clearDirSync(rootPath, saveSelf=true) {
// 检查目录是否存在
if(!isExist(rootPath)){
return;
}
// 获取:文件与子目录
let group = ls(rootPath);
if(Array.isArray(group.file) == false){ // 如果file属性不是一个数组,说明没查到东西。是个空文件夹。
return;
}
// 删除所有文件
group.file.map(f => fs.unlinkSync(f.path));
// 递归删除全部目录。
fs.rmdirSync(rootPath, true);
// 上面是直接递归删除整个目录,包括自己。这里判断一下,如果需要保留根目录,就再创建一下。
if(saveSelf){
mkdir(rootPath);
}
}
/**
* 清空目录下的文件(同步版)(只删除文件)
* @param {string} rootPath 要清空的目录
* @returns 被删除的文件列表
*/
function clearFilesSync(rootPath) {
try {
// 获取目录下的文件列表
const files = fs.readdirSync(rootPath);
// 删除所有文件
files.forEach(path => fs.unlinkSync(`${rootPath}/${path}`));
return files;
} catch (error) {
console.error(error);
}
}
/**
* 判断文件或目录是否存在
* @param {string} path 文件或目录路径
*/
function isExist(path){
try {
fs.accessSync(path);
return true;
} catch (err) {
console.log(`文件或目录不存在:${err.message}`);
return false;
}
}
/**
* 创建目录路
* 如果目录不存在就创建。
* @param {string} dirPath 文件夹路径
* @param {boolean} recursive 如果上级目录不存在,是否自动创建。默认:是
*/
function mkdir(path, recursive = true){
if(isExist(path) == false){ // 判断目录是否存在
fs.mkdirSync(path, recursive); // 如果没有就创建
}
}
/**
* 删除目录
* @param {string} path 要删除的目录路径 (本地路径)
* @param {boolean} recursive 是否递归删除目录。如果为 true,则删除该目录和该目录下的所有子目录以及文件
*/
function rmdirSync(path, recursive=false){
if(isExist(path)){ // 判断目录是否存在
fs.rmdirSync(path, recursive); // 如果存在就删除
}
}
/**
* 为文件名添加编号后缀
* @param {*} fileName 原文件名
* @param {*} suffixNumber 编号
* @param {*} suffixLen 编号位数
*/
function addSuffixNumber(fileName, suffixNumber, suffixLen) {
// 获取文件名与扩展名
let extension = '';
let index = fileName.lastIndexOf('.');
if (index !== -1) {
extension = fileName.substring(index);
fileName = fileName.substring(0, index);
}
// 计算后缀序号的位数
let suffixLength = Math.floor(Math.log10(suffixLen)) + 1;
// 对后缀编号进行高位补零
let paddedSuffixNumber = String(suffixNumber).padStart(suffixLength, '0');
// 返回新的文件名
return `${fileName}_${paddedSuffixNumber}${extension}`;
}
/**
* 高位补零
* @param {*} num 需要补零的序号
* @param {*} count 序号所在序列中,的总数。用于计算要补几位
* @param {*} suffixStr 自定补啥字符
*/
function padNumber(num, count=10, suffixStr='0') {
// 计算后缀序号的位数
let suffixLength = Math.floor(Math.log10(count)) + 1;
// 对后缀编号进行高位补零
return String(num).padStart(suffixLength, suffixStr);
}
/**
* 解析文件路径返回:{路径、全名、文件名、扩展名}
* @param {*} filePath 文件路径
*/
function getFileInfo(filePath) {
// 获取文件夹路径
const folderPath = filePath.substring(0, filePath.lastIndexOf('/') + 1);
// 获取文件名
const fileName = filePath.substring(folderPath.length, filePath.lastIndexOf('.'));
// 获取扩展名
const fileExtension = filePath.substring(filePath.lastIndexOf('.') + 1);
return {
path: folderPath,
fullName: `${fileName}.${fileExtension}`,
name: fileName,
extension: fileExtension
};
}
/**
* 读取本地文件内容。单个文件大小上限为100M。
* @param {*} filePath 文件路径。要读取的文件的路径 (本地路径)
* @param {*} encoding 指定读取文件的字符编码,如果不传 encoding,则以 ArrayBuffer 格式读取文件的二进制内容
* @param {*} position 默认从0开始读取。左闭右开区间 [position, position+length)。有效范围:[0, fileLength - 1]。单位:byte
* @param {*} length 指定文件的长度,如果不指定,则读到文件末尾。有效范围:[1, fileLength]。单位:byte
*/
function readFileSync(filePath, encoding='', position=0, length) {
return fs.readFileSync(filePath, encoding, position, length);
}
/**
* 写文件
* @param {*} filePath 文件路径。要写入的文件路径 (本地路径)
* @param {*} data 要写入的文本或二进制数据
* @param {*} encoding 指定写入文件的字符编码。默认 binary
*/
function writeFileSync(filePath, data, encoding='binary') {
fs.writeFileSync(filePath, data, encoding);
}
module.exports = {
fs,
chooseMediaZip,
chooseMedia,
chooseFile,
ls,
unlinkSync,
clearDir,
clearDirSync,
clearFilesSync,
isExist,
mkdir,
rmdirSync,
addSuffixNumber,
padNumber,
readFileSync,
writeFileSync
};