Electron实现文件断点下载和暂停下载

1,602 阅读1分钟

实现思路

  • 框架特点

Electron在主进程的窗口中开启nodeIntegration后,可以直接在渲染进程中使用node.js来进行文件IO操作

  • 断点下载
  1. 获取下载文件总大小 total_bytes
  2. 使用node读取已下载文件大小 received_bytes,在请求头中设置'range':'bytes=' + ${received_bytes}-${total_bytes}',服务端会返回'range'范围内的数据
  3. 使用request库请求下载url得到数据流,创建文件写入流并写入文件(注意:创建写入流时flags参数需要设置为'a',否则每次写入会覆盖之前已写入的数据)
  • 暂停下载

将创建的请求request和写入流stream关闭,可使用end()或destroy()方法,具体使用详见node官方文档nodejs.org/docs/latest…

代码实现(Vue2)

// 获取下载文件大小
const axios = require('axios')
async getFileSize(url) {
    return await axios
        .head(url)
        .then((res) => {
            return res.headers['content-length']
        })
        .catch((err) => {
            console.log(err)
        })
},
// 下载文件(通过id实现多文件下载)
const fs = require('fs')
const request = require('request')
const progress = require('progress-stream')

export default {
    data() {
        return {
            downloadList: {},
        }
    },
    methods: {
        downloadFile(total_bytes, path, url, id) {
            let stream, requestItem
            let received_bytes = 0
            try {
                // 获取已下载文件大小
                let stats = fs.statSync(path)
                if (total_bytes == stats.size) {
                    return
                }
                received_bytes = stats.size
            } catch (err) {}
            let params = {
                method: 'GET',
                url: url,
                headers: {},
            }
            if (received_bytes > 0) {
                params.headers['Range'] = 'bytes=' + `${received_bytes}-${total_bytes}`
            }

            stream = fs.createWriteStream(path, { flags: 'a' })
            requestItem = request(params)
            // 配合progress-stream库实现进度条功能
            let req_progress = progress({
                length: total_bytes,
                time: 1500,
            })
            let req = requestItem.pipe(req_progress).pipe(stream)
            this.$set(this.downloadList, id, {
                request: req,
                stream,
                percentage: 0,

            })
            req_progress.on('progress', (progress) => {
                const percentage = ((progress.transferred + received_bytes) / total_bytes) * 100
                const downloadItem = this.downloadList[id]
                if (downloadItem) {
                    this.$set(downloadItem, 'percentage', percentage)
                }
            })

            req.on('close', () => {
                const percentage = this.downloadList[id]?.percentage || 0
                if (percentage == 100) {
                    console.log(id, '下载完毕!')
                    this.$delete(this.downloadList, id)
                }
            })
        },
    }
}
// 暂停下载
cancelInstall(id) {
    this.downloadList[id].stream.end()
    this.downloadList[id].request.end()
    this.$delete(this.downloadList, id)
},