uniapp app端文件下载多个方式,包括大文件分片下载

1,534 阅读4分钟

不太会使用编辑器 我就贴些图和代码吧

这些是我经过最近一段时间查阅资料研究,得出的相对比较齐全uniapp app端文件下载方式

方式一

利用H5+的方法plus.downloader.createDownload,支持更改文件名,但只支持oss等网络文件,不支持文件流,支持app里的webview页面调用。

调用方式:downLoadFileAndSave('xxxxx.xls', 'lwq.xls')

// 创建文件夹,path值为:"/storage/emulated/0/自定义文件夹名称"

export const createDir = async(path) => {

  return new Promise((resolve, reject) => {

    // 申请本地存储读写权限

    plus.android.requestPermissions([

      'android.permission.WRITE_EXTERNAL_STORAGE',

      'android.permission.READ_EXTERNAL_STORAGE',

      'android.permission.INTERNET',

      'android.permission.ACCESS_WIFI_STATE'

    ], success => {

      const File = plus.android.importClass('java.io.File')

      const file = new File(path)

      // 文件夹不存在即创建

      if (!file.exists()) {

        file.mkdirs()

      }

      resolve()

    }, error => {

      uni.$u.toast('无法获取权限,文件下载将出错')

      reject(error)

    })

  })

}

/**

 * {url}  下载地址

 * {name}  保存文件时 重命名

 * {cb1,cb2}  下载进度和完成 的回调

 * :下载大文件“可能”会内存溢出

 * */

// downLoadFileAndSave('http://xxxxx.xls', 'lwq.xls')

export const downLoadFileAndSave = async(url, name, cb1, cb2) => {

  let progressVal = 0

  const osName = plus.os.name

  const path = '/storage/emulated/0/Download/Mro'

  try {

    if (osName === 'Android') {

      await createDir(path)

    }

    const selfName = url.split('/').pop() // 获取文件名

    if (!name) {

      name = selfName

    }

    const filename = osName === 'Android' ? 'file://' + path + '/' + name : '_downloads/' + name

    var dtask = plus.downloader.createDownload(url, {

      // filename: '_downloads/' + name // 利用保存路径,实现下载文件的重命名

      // filename: 'file://' + path + '/' + name // 利用保存路径,实现下载文件的重命名

      filename

    }, function(d, status) {

      // d为下载的文件对象

      if (status == 200) {

        console.log(osName + '下载成功', d)

        if (cb2) {

          cb2(d)

          return

        }

        // 下载成功,d.filename是文件在保存在本地的相对路径,使用下面的API可转为平台绝对路径

        // var fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename)

        // plus.runtime.openFile(d.filename) // 选择软件打开文件

        if (osName === 'Android') {

          uni.showToast({

            title: '文件已保存',

            icon: 'success'

          })

        } else {

          uni.showModal({

            title: '提示',

            content: '如需保存到本地,需要打开文件点击储存',

            // cancelText: '我知道了',

            confirmText: '打开文件',

            success: function(res) {

              if (res.confirm) {

                uni.openDocument({

                  filePath: d.filename,

                  success: (sus) => {

                    // console.log('成功打开')

                  }

                })

              }

            }

          })

        }

      } else {

        // 下载失败

        console.log('下载失败', d)

        plus.downloader.clear() // 清除下载任务

      }

    })

    dtask.addEventListener('statechanged', (task) => {

      if (!dtask) {

        return

      }

      switch (task.state) {

        case 1:

          console.log('开始下载')

          break

        case 2:

          console.log('链接到服务器...')

          break

        case 3:

          progressVal = (changeTwoDecimal_f(task.downloadedSize / task.totalSize) * 100) + '%'

          if (cb1) cb1(progressVal)

          break

        case 4:

          console.log('监听下载完成')

          break

      }

    })

  


    dtask.start()

  } catch (error) {

    console.log(error)

  }

}

  


/**

* 例如

* 2         →     2.00

* 2.3       →     2.30

* 2.321      →     2.32

* 2.328     →     2.33

*

* */

function changeTwoDecimal_f(x) {

  var f_x = parseFloat(x)

  if (isNaN(f_x)) {

    return 0

  }

  var f_x = Math.round(x * 100) / 100

  var s_x = f_x.toString()

  var pos_decimal = s_x.indexOf('.')

  if (pos_decimal < 0) {

    pos_decimal = s_x.length

    s_x += '.'

  }

  while (s_x.length <= pos_decimal + 2) {

    s_x += '0'

  }

  return s_x

}

效果图: 安卓的保存:

image.png

IOS的保存:

image.png

image.png

方式二:

特点:利用uni.downloadFile方法(只能是GET请求)+plus.io.convertLocalFileSystemURL等方法,通过uni.openDocument预览PDF、Excel、Word等文件,支持文件流、OSS文件下载 支持更改文件名,支持app里的webview页面调用。

调用方式:downLoadFileAndSave('xxxxx.xls', 'lwq.xls')

调用方式:downLoadFileAndSave('http://文件流的接口', 'lwq.xls')

handleDownload(url, name) {

      const that = this

      uni.downloadFile({ // 只能是GET请求

        url,

        header: {

          'Authorization': uni.getStorageSync('token')

        },

        success: (res) => {

          // 下载成功

          if (res.statusCode === 200) {

            // 拿到临时文件的绝对路径

            const filepathss = plus.io.convertLocalFileSystemURL(res.tempFilePath)

            // 通过这个路径来拿到他

            plus.io.resolveLocalFileSystemURL(filepathss, function(entry) {

              const tempFileName = entry.name

              entry.getParent(function(parentDicEntry) {

                entry.moveTo({ fullPath: parentDicEntry.fullPath + '/' }, name, function(newFile) {

                  that.handleOpen(newFile.fullPath)

                }, function(moveError) {

                  // uni.showToast({

                  //   title: `已在第三方应用中打开过,请在第三方应用查看时保存`,

                  //   icon: 'none'

                  // })

                  that.handleOpen(parentDicEntry.fullPath + '/' + name)

                })

              })

            })

          }

        },

        fail: (e) => {

          this.isDownloading = false

          uni.showToast({

            title: `文件下载失败`,

            icon: 'none'

          })

        }

      })

    },

    handleOpen(filePath) {

      uni.showModal({

        title: '提示',

        content: '如需保存到本地,需要打开文件再保存',

        // cancelText: '我知道了',

        confirmText: '打开文件',

        success: function(res) {

          if (res.confirm) {

            // 保存成功之后 打开文件

            uni.openDocument({

              filePath,

              fail: (e) => {

                uni.showToast({

                  title: `打开失败,可先安装office软件(WPS)再尝试打开`,

                  icon: 'none',

                  duration: 2000

                })

              }

            })

          }

        }

      })

    },

方式三:

特点:利用uni.request arraybuffer,plus.io里的writer.writeAsBinary(base64)方法,通过uni.openDocument预览PDF、Excel、Word等文件,支持文件流、OSS文件下载 支持更改文件名,支持app里的webview页面调用。

writer.writeAsBinary(base64) 这个方法非常重要,对后续的大文件分片下载非常有帮助。

调用方式:如下

uni.request({

        url: '文件流接口 或 http:/xxxx.xls', // 支持文件流、OSS文件下载

        method: 'GET',

        responseType: 'arraybuffer',

        header: {

          'Authorization': 'Bxxx'

        },

        success: (res) => {

          const base64 = uni.arrayBufferToBase64(res.data)

          const filePath = '_documents/xxxx.xls' // 自定义路径

          // 写入文件

          plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function(fs) {

            fs.root.getFile(filePath, { create: true }, function(fileEntry) {

              fileEntry.createWriter(function(writer) {

                writer.onwrite = function(e) {

                  plus.nativeUI.alert('文件已保存', function() {

                    plus.runtime.openFile(filePath) // 打开文件

                  })

                }

                writer.onerror = function(e) {

                  console.error('写入失败: ' + e.message)

                }

                // writer.write(res.data)

                writer.writeAsBinary(base64)

              }, function(e) {

                console.error('创建Writer失败: ' + e.message)

              })

            }, function(e) {

              console.error('获取文件失败: ' + e.message)

            })

          }, function(e) {

            console.error('请求文件系统失败: ' + e.message)

          })

        }

      })

方式四:大文件分片下载

上面3种下载方式是我经过最近一段时间查阅资料苦逼研究出来的,其中方式三更是如此,得出的相对比较齐全uniapp app端文件下载方式。

至于方式四大文件分片下载,全网没找到实现方法,几经波折自己硬啃下来,但文件较大时写入问题有问题,最终还是得采取跳转浏览器打开页面下载的方式。