微信小程序开发技巧总结(二) -- 文件的选取、移动、上传和下载

微信小程序开发技巧总结(二) -- 文件的选取、移动、上传和下载

1.不同类型文件的选取

1.1 常用的图片 视频

对于大部分开发者来说,需要上传文件形式主要为图片,微信为此提供了接口。

wx.chooseImage({
  count: 1,sizeType: ['original','compressed'],sourceType: ['album','camera'],success (res) {
    // tempFilePath可以作为img标签的src属性显示图片
    const tempFilePaths = res.tempFilePaths
  }
})

其次为视频文件的选取,微信也为此提供了接口。

wx.chooseVideo({
  sourceType: ['album',maxDuration: 60,//视频长度 单位 s
  camera: 'back',//选取前置  摄像 还是 后置 摄像
  success(res) {
    console.log(res.tempFilePath)
  }
})

也为其提供了视频和图片的二合一接口,这个接口不建议调用图片和视频的上传建议区分开。

wx.chooseMedia({
  count: 9,mediaType: ['image','video'],maxDuration: 30,camera: 'back',success(res) {
    console.log(res.tempFilePath)con
    console.log(res.size)
  }
})

这几个接口调用成功的回调函数中,都返回的是文件文件在本机中的路径。

res.tempFilePath

这是一个 数组,存放着选择的所有文件的路径,用于上传

1.2 其余形式各种文档

那么如果是想要在小程序上传 doc、pdf、ppt 等类型的文件怎么处理?首先要注意的是微信小程序并没有给用户提供文件管理器接口。

开发者:我想要个文件管理器接口!

官方:不,你不想

聪明的开发者他没有办法,只能另辟蹊径。微信提供了一个选择客户端会话文件方法

wx.chooseMessageFile({
   success(res){
       console.log(res.tempFilePath)
    }
})

与上面两个接口相同,返回的也是文件在本地的存储路径,但是不同的是,这个接口可以选取全部的文件类型。

开发者如果想要上传图片和视频内容的话,需要两步走。

  1. 打开微信文件传输助手,将想要上传文件发送到文件传输助手
  2. 小程序调用这个接口,选择文件传输助手,从会话中选择想要上传文件

2.文件上传

2.1 uploadFile方法

所有的文件都是以字节流的形式进行上传,所以上传形式并没有什么本质区别,都是调用相应的接口进行上传

小程序端写法如下:

wx.uploadFile({
      url: '你的服务器函数地址',//仅为示例,非真实的接口地址
      filePath: '需要上传文件路径',//res.tempFilepaths
      name: 'file',// 文件对应的key ,默认 为 file
      formData: {
        'user': 'test'
      },//上传额外携带的参数
      success (res){
        const data = res.data
        //do something
      }
})

2.2 服务器端如何处理上传文件

服务端如何接受文件上传?仅展示Java方式(SpringBoot 框架)

@Controller
@ResponseBody
public class FileController {
    //文件上传控制类,是核心配置类,Win <->Linux
    @RequestMapping(value = "/upload/images")
    public String uploadimages(HttpServletRequest request,@RequestParam("file") MultipartFile file,@RequestParam("user") String user) throws IOException {
       //更换服务器,这个值也需要修改
        //图片上传写法
        //type 是上传图片的类型
        if(!file.isEmpty()){
            //文件不为空
            //String path = "E:"+File.separator+"images"+File.separator+type; // this is windows method
            String path = "/share"+File.separator+"images"+File.separator+type;
            // this is Linux method
            String filename = file.getOriginalFilename();
            File filepath = new File(path,filename);//新建文件存储路径
            System.out.println(filepath);
            if(!filepath.getParentFile().mkdirs()){
                filepath.getParentFile().mkdirs();
            }
            file.transferTo(new File(path+File.separator+filename));
           //想要返回可直接访问的链接还要配置 映射,具体请看下面链接
            return "你的IP地址"+"/images/"+type+"/"+filename;
        }else {
            return "error";
        }
    }
}

配置访问映射

文件访问映射

2.3 云开发文件上传

微信小程序支持云开发,其文件上传接口有一些差异,但是不需要自己再构建后台

wx.cloud.uploadFile({
  cloudPath: 'file/' + '你的文件名字(带格式后缀)',// 在云端存储的路径
  filePath: '',// 就是选择文件返回的路径
}).then(res => {
  // get resource ID
  console.log(res.fileID)
}).catch(error => {
  // handle error
})

我们可以根据返回的fileID 置换 真实的文件访问地址。

其置换方式参见官方文档:

wx.cloud.getTempFileURL({
  fileList: ['cloud://xxx','cloud://yyy'],success: res => {
    // get temp file URL
    console.log(res.fileList)
  },fail: err => {
    // handle error
  }
})

TIPS:关于云开发文件上传的建议

  1. 如果没有保密需求,为了方便后续开发,存储到数据库中的最好是可以直接访问的文件链接
  2. 置换真实文件地址,不要每次上传一次文件就置换一次,先把返回的fileID 存放在数组中,到该事务所有上传完成后,再使用fileID 数组置换真实文件访问链接数组。
  3. 要考虑文件名重复的可能,建议使用时间戳在 wx.cloud.uploadFile 中的 cloudPath 中对存储到云环境中的文件命名进行格式化。

总的来说就是先上传文件,再向数据库中写入记录。

2.4 多文件同时上传的处理方式

uploadFile 每次只能上传一个文件

如何处理这个问题?

A.不考虑文件上传次序问题,可以采用遍历上传的方式,采用精确的时间戳和遍历index对文件名进行格式化。通过定时触发检测函数判断是否全部上传完成。这种方式考虑的是并发能力。

upSeveralfiles() {
      wx.showLoading({
        title: '上传中~',mask: true
      })
      var that = this;
      var timecode = sev.vcode(new Date()); // 这是时间戳编码函数
      var files = this.data.fileList;       // 这是 选择文件中返回的 res.tempFilePath 数组
      var len = files.length;
      var i = 0;
      for (i = 0; i < len; i++) {
        var str = files[i].name;
        wx.cloud.uploadFile({
          cloudPath: 'file/' + '(' + sev.getformatTime(new Date()) + ')' + str,filePath: files[i].path,success(res) {
            console.log(res)
            that.setData({
              cloudlist: that.data.cloudlist.concat([res.fileID]),})
             // cloudlist 是存放 文件链接置换id 的数组,非云开发存储的就是真实可访问的链接数组
             // 如果使用的不是云开发 那么 可以返回真实的 访问地址
          },fail(res) {
            console.log(res)
          }
        })
      }
    // 使用定时器检测文件是否全部上传完成,并 判断是否进行下一步 操作
      var timer = setInterval(function () {
        if (that.data.cloudlist.length == len) {
          // 只有全部上传成功了 长度才会相等
          clearInterval(timer);
          // 继续执行下一步 ,根据 cloudlist 置换真实地址 并存放到数据库
          // 如果使用的非云开发,那么就继续执行 存储至数据库的操作
        }
      },1000)
   }

补充文件编码函数 sev.js 中的根据时间编码部分,可以根据实际流量自定义

function getformatTime(date) {
  var year = date.getFullYear()
  var month = date.getMonth() + 1
  var day = date.getDate()

  var hour = date.getHours()
  var minute = date.getMinutes()
  var second = date.getSeconds()

  return [year,month,day].map(formatNumber).join('-');
};

B.考虑文件上传次序问题,采用回调方式进行文件上传(更推荐使用这种方式)

data: {
    fileList: [],realList: [],//云端地址链接列表
    fileid: 0,},upSeveralfiles() {
    var that = this;
    var files = this.data.fileList;       // 这是 选择文件中返回的 res.tempFilePath 数组
    var len = files.length;
    var uid = this.data.fileid;
    wx.uploadFile({
      url: '你的服务器文件接收函数请求地址',name: 'file',filePath: files[uid],header: {
        "Content-Type": "multipart/form-data"
      },success(res) {
        that.setData({
          fileid: uid + 1,realList: that.data.realList.concat([res.data])
        },() => {
          if (that.data.fileid == len) {
            // 上传完成,执行下一步操作
              
          } else {
              //上传完一个文件 递归执行 下次上传
            that.upSeveralfiles();
          }
        })
      },fail(res) {
        console.log(res.data)
      }
    })

  },

以上是提供的两种思路,无论是不是云开发,两种思路都是共通的,适用于多文件上传.

3.文件的下载

这个地方唯一值得注意的是云开发的一种下载方式 可以通过fileID进行download,当然只能下载存储在自己云环境中的文件.

wx.cloud.downloadFile({
  fileID: '',success: res => {
    console.log(res.tempFilePath)
  },fail: err => {
  }
})
wx.downloadFile({
  url: '',//仅为示例,并非真实的资源
  success (res) {
     //res.tempFilePath
})

下载进度监控,用于下载进度条绘制等功能实现

const downloadTask = wx.cloud.downloadFile({ *** }) // wx.downloadFile 同理
downloadTask.onProgressUpdate((res) => {
    //res.progress 为下载进度
})

下载下来的文件支持直接打开,就像是在微信聊天中打开一样,需要下载插件

其使用方式为:

wx.openDocument({
     filePath: res.tempFilePath //为文件路径 非数组,可使用回调函数 success 等
})

4.文件的移动

这个一般情况下是用不到的,也不建议使用移动文件方法作为功能实现手段,必然有更好的替代方式,比如修改数据库路径 和 真实文件路径的映射,效率更高一些.

这里仅讲云开发移动文件方式。

const cloud = require('wx-server-sdk')
const fs = require('fs')
const path = require('path')

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})

exports.main = async (event,context) => {
  const fileStream = fs.createReadStream(path.join(__dirname,'demo.jpg'))
  //这个可以读取 云存储 中的文件 , 所谓删除 就是复制 然后 删除原位置文件
  return await cloud.uploadFile({
    cloudPath: 'demo.jpg',fileContent: fileStream,})
}

具体开发文档

建议在数据库修改映射路径最好。

需要小程序开发的请联系我QQ : 1025584691

相关文章

1. 获取输入框数据wxml中的input上增加bindinput属性,和方法值在js部分定义与之对应的方法,只要在输入...
1.map组件的高度如果想要铺满屏幕,要是使用height:100vh样式2.获取位置要在app.json中标明权限3.先使用...
QQ小程序支付 Java后端 同学折腾QQ小程序的支付折腾了好几天,没有完成统一下单,因为我做过微信和支付...
前言: 在实际项目开发中我们经常会遇到账号统一的问题,如何在不同端或者是不同的登录方式下保证同一个...
一、前言: 我发现很多的同学都在抱怨说微信小程序的picker的mode = selector/mode = multiSelector 无...
前言: 之前自己做一个uni-app的项目的时候前端需要实现一个比较复杂的动态tab和swiper切换的功能,但是...