微信小程序 - PC端选择ZIP文件

微信小程序 - PC端选择文件

分享代码片段

不想听废话的,直接看代码。
https://developers.weixin.qq.com/s/UL9aojmn7iNU

场景分析

如果你的微信小程序需要选中 ZIP 包,然后解压并处理其中的文件。

对于移动端可以使用 wx.chooseMessageFile(Object object) 来实现,它支持从客户端会话选择文件。

但不幸的是PC端,并不支持此API。官方也没有给出别的API。(当然论坛里有提到一个曲线解决方案,申请个企业号,用webview实现选择文件。网上有讨论的,这里就不细聊了。)

但是对于个人号来说,这就尴尬了。一是没有权限使用webview,二是纯前端的小程序,为了选择文件还得加个服务器,有点不值当。

所以想到了一个曲线的解决方案。利用:chooseMedia

解决思路

  1. 虽然PC端不支持 wx.chooseMessageFile 但支持 wx.chooseMedia 这个API是用来选择媒体文件的,比如:视频、图片。
  2. 通过测试,直接将 zip 的扩展名改为 PNG 是无效的。因为选择后,它会检查文件头,过滤掉不符合的,最终只能拿到真实的PNG文件。
  3. 既然它是校验了文件头,那我们就给ZIP文件前加上PNG的文件名,然后通过 wx.chooseMedia 获取到文件后,再跳过我们自己的 PNG头,把剩余的ZIP部分读出来,保存为一个正常的 ZIP 文件。
  4. 然后就可以正常解压或读取 ZIP 压缩包了。

附魔脚本

PNG头加到ZIP文件前面,可以使用下面这个脚本实现。

这是附魔的bat脚本,通过在zip前添加25个字节,是PNG文件的头89504E470D0A1A0A0000000D49484452转成的base64

bash 复制代码
echo iVBORw0KGgoAAAANSUhEUg==>_________
copy /b _________ + /b %1 %~nx1.png
del /q _________

zip拖到脚本上之后,即可生成一个 xxx.zip.png 文件。

chooseMediaZip 选择附魔后的ZIP文件

javascript 复制代码
const fs = wx.getFileSystemManager();

/**
 * 选择媒体附魔的ZIP
 * @param {object} options 
 */
function chooseMediaZip(options = {}){
  const defaultOptions = { 
    count: 9,                                 // 单次选择数量上限
    mediaType: ['image'],                     // 选择框支持的文件类型
    encoding: 'binary',                       // 编码类型,默认 'binary'。想写文本用 'utf8'
    folder: `${wx.env.USER_DATA_PATH}/jerry`, // 保存二进制文件的路径
    suffix: 'zip'                             // 二进制文件的扩展名
  };
  let params = {...defaultOptions, ...options};
  return wx.chooseMedia(params) // 选择 *.zip.png 文件
  .then(res=>{ // 跳过 PNG 读取出实际二进制数据
    return res.tempFiles.map(tempFile=> {
      // 跳过PNG头25字节,从26开始读取 zip 的二进制部分
      const arrayBuffer  = readFileSync(tempFile.tempFilePath, '', 26);
      console.log(arrayBuffer);
      // 写 二进制文件 到目录 path
      const file = {};
      file.name = `${Date.now()}.${suffix}`;
      file.path =`${ params.folder }/${ file.name }`;
      mkdir(params.folder); 
      writeFileSync( file.path, arrayBuffer, encoding ); // 写 二进制 文件
      return file; // {name: 'fileName', path: 'http://xxx.xxx'}
    });
  }).catch(console.error);
}

相关方法

chooseMedia 需要用到的几个方法

javascript 复制代码
/**
 * 判断文件或目录是否存在
 * @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 {*} filePath 文件路径。要写入的文件路径 (本地路径)
 * @param {*} data 要写入的文本或二进制数据
 * @param {*} encoding 指定写入文件的字符编码。默认 binary
 */
function writeFileSync(filePath, data, encoding='binary') {  
  fs.writeFileSync(filePath, data, encoding);
}

测试方法

javascript 复制代码
test(e){
    fileUtil.chooseMediaZip({ 
      count: 9,                                 // 单次选择数量上限
      mediaType: ['image'],                     // 选择框支持的文件类型
      encoding: 'binary',                       // 编码类型,默认 'binary'。想写文本用 'utf8'
      folder: `${wx.env.USER_DATA_PATH}/jerry`, // 保存二进制文件的路径
      suffix: 'zip'                             // 二进制文件的扩展名
    }).then(res => {
      res.forEach(zip => {
        fs.readZipEntry({
          'filePath': zip.path,
          'entries': 'all',
          success: res => console.log(res.entries), // zip中的文件列表
          fail: err => console.log(err)
        });
      });
    });
  }

参考资料

判断文件/目录是否存在(同步版) FileSystemManager.accessSync(string path)
创建目录(同步版) FileSystemManager.mkdirSync(string dirPath, boolean recursive)
写文件(同步版) FileSystemManager.writeFileSync(string filePath, string|ArrayBuffer data, string encoding)

相关推荐
万岳科技系统开发2 小时前
私域直播小程序源码的整体架构设计与实现思路
学习·小程序
ee82ee2 小时前
uniapp小程序底部键盘唤起问题处理,包含间隙处理,动画处理
微信小程序
qq_12498707533 小时前
基于springboot健康养老APP的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·mysql·微信小程序·毕业设计
汤姆yu3 小时前
基于微信小程序的驾校预约与学习系统
学习·小程序·驾校预约
夏源3 小时前
【微信小程序】实现引入 Echarts 并实现更新数据
微信小程序
speedoooo4 小时前
未来的App不再需要菜单栏?
前端·ui·容器·小程序·web app
猿究院_xyz5 小时前
微信小程序与echarts联动安卓真机测试出现黑色阴影
前端·javascript·微信小程序·小程序·echarts
说私域6 小时前
不同类型企业构建私域流量的必要性及定制开发AI智能名片商城小程序的应用
大数据·人工智能·小程序
老华带你飞7 小时前
健身房预约|基于springboot 健身房预约小程序系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·小程序
2501_915909067 小时前
苹果应用加密方案的一种方法,在没有源码的前提下,如何处理 IPA 的安全问题
android·安全·ios·小程序·uni-app·iphone·webview