简介
前端用 Blob 分割文件,定义好每一段数据的大小,首先要把文件信息,包括文件名、文件大小、校验值、分段大小等信息发给服务器。然后是执行每一段的发送任务,可异步(有待研究,是开多个ws连接还是?🤔)也可同步(服务端最好要有回应事件),异步的话需要注意文件段的顺序,最好的话同步异步都用自己定义个格式帧去传输,方便校验。这里是简单版的,直接发送,没有校验! 还有,分段下载也是一样的操作~
前端
前端用的是 ant-design-vue upload组件,customRequest
自定义上传。
<a-upload
name="file"
:file-list="fileList"
:customRequest="customRequest"
@change="handleChange"
>
<a-button>
<a-icon type="upload"/>
Click to Upload
</a-button>
</a-upload>
methods
customRequest (options) {
const blob = options.file
// 每个文件切片大小
const bytesPerPiece = 40960
let start = 0
let end
while (start < blob.size) {
end = start + bytesPerPiece
if (end > blob.size) {
end = blob.size
}
// 切割文件
const chunk = blob.slice(start, end)
// 发送数据到服务器
this.$global.ws.send(chunk)
start = end
}
// 表示发送完毕
this.$global.ws.send(new Blob(['end'], {type: 'text/plain'}))
// 表示已经上传成功 ...
const reader = new FileReader()
reader.readAsDataURL(options.file)
reader.onload = () => {
options.onSuccess()
}
}
效果
前端发送数据
后台接收数据
后台代码
package com.xxx.sdk.server;
import com.xxx.sdk.protocol.r2000.upgrade.ReadFile;
import com.xxx.sdk.util.AsciiUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Rubin
* @version v1 2020/12/11 14:19
*/
public class WsUploadFileHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame> {
/**
* 分段数据
*/
List segmentedData = new ArrayList<>();
/**
* 文件总字节数
*/
AtomicInteger fileLength = new AtomicInteger(0);
@Override
protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame msg) {
ByteBuf content = msg.content();
int readableBytes = content.readableBytes();
byte[] bytes = new byte[readableBytes];
content.getBytes(0, bytes);
if (readableBytes == 3) {
// 文件传输完毕
if ("end".equals(AsciiUtil.hex2AsciiStr(bytes))) {
// 拼接分段的数据
byte[] file = new byte[fileLength.get()];
// 拷贝下标
AtomicInteger fileIndex = new AtomicInteger();
segmentedData.forEach(fbs -> {
int length = ((byte[]) fbs).length;
System.arraycopy(fbs, 0, file, fileIndex.get(), length);
fileIndex.addAndGet(length);
});
// 读取完整文件
ReadFile.read(new ByteArrayInputStream(file));
}
} else {
segmentedData.add(bytes);
fileLength.addAndGet(bytes.length);
}
}
}
楼主的是单机本地程序,所以是理想环境,校验啥的都没有,网络应用的话数据完整性校验可不能少!
大文件的话还可以做个进度条啥的,哈哈哈😄