微信小程序 - 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)

相关推荐
丁总学Java6 小时前
微信小程序,点击bindtap事件后,没有跳转到详情页,有可能是app.json中没有正确配置页面路径
微信小程序·小程序·json
说私域7 小时前
基于开源 AI 智能名片、S2B2C 商城小程序的用户获取成本优化分析
人工智能·小程序
mosen8687 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
qq22951165028 小时前
微信小程序的汽车维修预约管理系统
微信小程序·小程序·汽车
尚梦15 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
小飞哥liac18 小时前
微信小程序的组件
微信小程序
stormjun19 小时前
Java基于微信小程序的私家车位共享系统(附源码,文档)
java·微信小程序·共享停车位·私家车共享停车位小程序·停车位共享
paopaokaka_luck20 小时前
基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)
java·spring boot·小程序·毕业设计·mybatis·1024程序员节
Bessie2341 天前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
shenweihong1 天前
javascript实现md5算法(支持微信小程序),可分多次计算
javascript·算法·微信小程序