本地分块上传文件
注意,该功能已经下架。
下架原因:该功能用量少,没有适合场景。
实现原理:通过 UDP 上传数据,上传数据的时候,将文件切割,然后上传固定长度的数据。
wxml 文件
<view class="page">
<view class="weui-form">
<view class="weui-form__bd">
<view class="weui-form__text-area">
<h2 class="weui-form__title">分块上传视频文件</h2>
<view class="weui-form__desc">打开手机WIFI后,可将本手机的视频文件上传到局域网内的服务器。</view>
</view>
<view class="weui-form__control-area">
<view class="weui-cells__group weui-cells__group_form">
<view class="weui-cells__title">地址信息</view>
<view class="weui-cells">
<view class="weui-cell weui-cell_active">
<view class="weui-cell__hd"><label class="weui-label">UDP地址</label></view>
<view class="weui-cell__bd">
<input class="weui-input" placeholder="IP地址:端口号" placeholder-class="weui-input__placeholder" name="addr" bindblur="getAddr" />
</view>
</view>
</view>
<view class="weui-cells__tips weui-cells__tips_warn " style="{{isErr ? 'display:block' : 'display:none'}}">错误提示:{{tips}}</view>
</view>
<view class="weui-cells__group weui-cells__group_form">
<view class="weui-cells__title">文件信息</view>
<view class="weui-cells weui-cells_form">
<view class="weui-cell weui-cell_uploader">
<view class="weui-cell__bd">
<view class="weui-uploader">
<view class="weui-uploader__hd">
<view aria-role="option" class="weui-uploader__overview">
<view class="weui-uploader__title">选择视频文件</view>
</view>
<view class="weui-uploader__tips">
请选择单个哟
</view>
</view>
<view class="weui-uploader__bd">
<view class="weui-uploader__files" id="uploaderFiles">
<block wx:for="{{files}}" wx:key="*this">
<view class="weui-uploader__file" bindtap="viewVideo" id="{{item}}">
<video class="weui-uploader__img" src="{{item}}" />
</view>
</block>
</view>
<view class="weui-uploader__input-box">
<view aria-ro le="button" aria-label="选择视频" class="weui-uploader__input" bindtap="getVideo"></view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="weui-cells__group weui-cells__group_form">
<view class="weui-cells__title">传输信息</view>
<view class="weui-cells weui-cells_form">
<view class="weui-cell" hover-class="weui-cell_active">
<view class="weui-cell__bd">
<progress percent="{{pi}}" stroke-width="3" show-info="true"/>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="weui-form__ft">
<view class="weui-form__tips-area">
<view class="weui-form__tips">
{{tips}}
</view>
</view>
<view class="weui-form__opr-area">
<button aria-role="button" class="weui-btn weui-btn_primary" bind:tap="doTransFile">上传文件</button>
</view>
</view>
</view>
</view>
wxss 文件
.weui-form {
padding-top: 64rpx;
}
.page{
height: 100%;
}
js 文件
const utils = require("../../utils/utils.js");
import MyUdp from './myUdp.js';
const UdpPacketSize = 1038; // 单位为字节
const UdpContentSize = 1024; // 单位为字节
var cu = null; // udp句柄
var buf = null; // 缓存
var bufidx = 0; // 缓存索引
var sendCnt = 0; // 发送计数
var pieceIdx = 0; // 块计数
var pkgIdx = 0; // 包计数
Page({
/**
* 页面的初始数据
*/
data: {
ip: '',
port: 0,
files: [],
pi: 0,
fileType: '',
fileSize: 0,
cacheSize: 0,
pieceCount: 0,
},
// 选择视频
getVideo() {
const that = this;
wx.chooseMedia({
count: 1,
mediaType: ['video'],
sourceType: ['album'],
sizeType: ['original'],
success(res) {
var tempFiles = res.tempFiles;
const tfp = tempFiles[0].tempFilePath;
let fileType = utils.getExtension(tfp);
let myfiles = [];
myfiles.push(tfp);
let fz = tempFiles[0].size;
let bk1 = Math.ceil(fz / UdpContentSize);
let bk2 = bk1 * UdpContentSize;
console.log('文件大小,', fz, bk2);
that.setData({
files: myfiles,
fileSize: fz,
fileType: fileType,
pieceCount: bk1,
cacheSize: bk2,
pi: 0,
});
console.log('debug,', that.data.files, that.data.fileSize, that.data.fileType)
if (!utils.isEmpty(cu)) {
cu.close()
}
cu = null; // udp句柄
buf = null; // 缓存
bufidx = 0; // 缓存索引
sendCnt = 0; // 发送计数
pieceIdx = 0; // 块计数
pkgIdx = 0; // 包计数
},
});
},
// 预览视频
viewVideo(e) {
wx.previewMedia({
current: e.currentTarget.id,
sources: [{
url: this.data.files[0],
type: 'video',
}],
});
},
getAddr(e) {
const that = this;
let obj = e.detail.value;
console.log('addr,', obj);
const objArr = utils.str2arr3(obj);
that.setData({
ip: objArr[0],
port: Number(objArr[1]),
})
},
// 获取文件内容
getFileContent() {
const that = this;
try {
const filePath = that.data.files[0];
const fs = wx.getFileSystemManager()
const res = fs.readFileSync(filePath)
console.log(res.byteLength);
return res;
} catch (e) {
console.error(e)
}
},
// udp 错误监听
uErr(res) {
console.log('udp err,', res.errMsg);
const that = this;
// 关闭udp
cu.close();
},
// UDP消息
uMsg(res) {
// console.log('recv msg,', res);
const that = this;
const msg = res.message;
const mdv = new DataView(msg);
const tag = mdv.getUint16(0, true);
// console.log('tag,', tag);
// 收到确认数据
if (tag == 0x0002) {
// console.log('t1,',pieceIdx,that.data.pieceCount)
if (pieceIdx >= that.data.pieceCount) {
console.log('已经发送完毕');
sendCnt = sendCnt + 1;
pkgIdx = pkgIdx + 1;
const ab = new ArrayBuffer(10);
const dv = new DataView(ab);
dv.setUint16(0, 0x0005, true);
dv.setUint32(2, 4, true);
dv.setUint32(6, pkgIdx, true);
cu.send(that.data.ip, that.data.port, ab);
} else {
pkgIdx = pkgIdx + 1;
const ab = new ArrayBuffer(UdpPacketSize);
const dv = new DataView(ab);
dv.setUint16(0, 0x0003, true);
dv.setUint32(2, 1032, true);
dv.setUint32(6, pkgIdx, true);
dv.setUint32(10, 0, true);
// 复制内容
// console.log('t2,',bufidx,that.data.cacheSize)
if (bufidx <= that.data.cacheSize) {
utils.copyBuffer(ab, 14, buf, bufidx, bufidx + UdpContentSize);
bufidx = bufidx + UdpContentSize;
cu.send(that.data.ip, that.data.port, ab);
}
// 计数
sendCnt = sendCnt + 1;
pieceIdx = pieceIdx + 1;
let pi = Math.ceil(pieceIdx / that.data.pieceCount * 100);
that.setData({
pi: pi,
})
}
}
},
doTransFile() {
const that = this;
console.log("开始分块上传文件");
console.log("文件大小为,", that.data.fileSize);
console.log("文件缓存为,", that.data.cacheSize);
console.log("文件被分成切片数量,", that.data.pieceCount);
console.log("当前时间为,", utils.getNowStr());
if (utils.isEmpty(that.data.files)) {
wx.showToast({
title: '请选择文件',
})
return
}
// 初始化udp
cu = new MyUdp();
cu.setup(that.uMsg, that.uErr)
bufidx = 0;
buf = new ArrayBuffer(that.data.cacheSize);
const fileContent = that.getFileContent();
utils.copyBuffer(buf, 0, fileContent, 0, that.data.fileSize);
// u32 文件大小 u32 缓存大小 u32 文件类型 u32 切片数量
sendCnt = sendCnt + 1;
pkgIdx = 1
let fileTypeCode = utils.getFileTypeCode(that.data.fileType);
let ab = new ArrayBuffer(30);
let dv = new DataView(ab);
dv.setUint16(0, 0x0001, true);
dv.setUint32(2, 24, true);
dv.setUint32(6, pkgIdx, true);
dv.setUint32(10, 0, true);
dv.setUint32(14, that.data.fileSize, true);
dv.setUint32(18, that.data.cacheSize, true);
dv.setUint32(22, fileTypeCode, true);
dv.setUint32(26, that.data.pieceCount, true);
// console.log('ab,', ab, ab.byteLength);
cu.send(that.data.ip, that.data.port, ab);
console.log('send start');
},
})