1. 程式人生 > >微信小程式開發技巧總結(二) -- 檔案的選取、移動、上傳和下載

微信小程式開發技巧總結(二) -- 檔案的選取、移動、上傳和下載

微信小程式開發技巧總結(二) -- 檔案的選取、移動、上傳和下載

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','camera'],
  maxDuration: 60, //視訊長度 單位 s
  camera: 'back', //選取前置  攝像 還是 後置 攝像
  success(res) {
    console.log(res.tempFilePath)
  }
})

也為其提供了視訊和圖片的二合一介面,這個介面不建議呼叫,圖片和視訊的上傳建議區分開。

wx.chooseMedia({
  count: 9,
  mediaType: ['image','video'],
  sourceType: ['album', 'camera'],
  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)
      }
    })

  },

以上是提供的兩種思路 , 無論是不是雲開發 , 兩種思路都是共通的,適用於多檔案上傳.

  1. 檔案的下載

這個地方唯一值得注意的是雲開發的一種下載方式 可以通過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 等
})
  1. 檔案的移動

這個一般情況下是用不到的, 也不建議使用移動檔案的方法作為功能實現手段 ,必然有更好的替代方式,比如修改資料庫路徑 和 真實檔案路徑的對映, 效率更高一些.

這裡僅講雲開發移動檔案方式。

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 : 1025584