Java分片上传全解决方案,真香
“持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情”
因为我们是做语音识别的,在离线的情况下,需要上传语音,但是因为语音很大,
所以需要拆分进行上传,要不然如果网络波动就前功尽弃了,今天就来复述下这个方案
1、解决方案
我们的方案是
第一步需要创建转写任务,返回给前段一个taskId。
第二步就是分片上传语音,每次只能上传一片语音,并且是顺序上传。
在最后一片上传完成后进行合成并且执行任务。如果失败了下次继续上传就可以了
2、show code
看一下我们分片上传的时候一些请求参数。
主要的参数有两个。
一个是sliceIndex,表示当前是第几个分片
一个是sliceTotal,表示总共有多少个分片,在最后一个的时候触发合并任务。
/**
* 产品id 必传
*/
private String productId;
/**
* 任务Id
*/
private String taskId;
/**
* 文件名
*/
private String fileName;
/**
* 当前分片的索引 从 1 开始
*/
private Integer sliceIndex;
/**
* 总共多少片 最后一个会触发合并任务
*/
private Integer sliceTotal;
下面是合并文件的代码:
/**
* 合并文件夹下的文件
*
* @param fold 所在文件夹
* @param fileName 原文件的名字
* @return
* @throws Exception
*/
public static String mergeFiles(File fold, String fileName) throws Exception {
if (fold == null) {
throw new BadRequestException("参数错误");
}
File[] files = fold.listFiles();
if (files == null || files.length == 0) {
throw new BadRequestException("参数错误");
}
File resultFile = new File(fold, fileName);
if (files.length == 1) {
files[0].renameTo(resultFile);
return resultFile.getAbsolutePath();
}
List<File> collect = Arrays.stream(files)
.filter(f -> f.getName().lastIndexOf("_") != -1)
.sorted((o1, o2) -> {
int idx1 = Integer.parseInt(o1.getName().substring(o1.getName().lastIndexOf("_") + 1));
int idx2 = Integer.parseInt(o2.getName().substring(o2.getName().lastIndexOf("_") + 1));
return idx1 - idx2;
}).collect(Collectors.toList());
FileChannel resultFileChannel = new FileOutputStream(resultFile, true).getChannel();
for (File f : collect) {
FileChannel blk = new FileInputStream(f).getChannel();
resultFileChannel.transferFrom(blk, resultFileChannel.size(), blk.size());
blk.close();
}
resultFileChannel.close();
for (int i = 0; i < files.length; i++) {
files[i].delete();
}
return resultFile.getAbsolutePath();
}
3、技术解析
知识点一:
如果上传的文件只有一个,直接进行改名就可以了。不需要合成
知识点二:
因为在上传的时候,每个分天的保存在后缀加索引,是为了在合成的时候进行顺序合成。
所以在合成之前需要先对文件进行排序
知识点三:
这里直接使用了FileChannel,比原来的stream效率更高
知识点四:
FileChannel要及时关闭。原来的分片任务这里进行了删除。
4、测试
一般情况下,分片上传是由前端调用。但是在开发的过程中,需要我们自己去测试接口。所以需要自己去切分文件。
方案一:
在最初的时候,我拿了一个小文件。大概2M,直接使用sublime打开。从其中拷贝字节。存到另外一个文件里。相当于进行了切分。
方案二:
自己写程序进行切换,这里将文件切分成1M大小。
public static void splitFile() throws IOException {
FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\xin.chong\\Desktop\\aispeech-aichat\\明月几时有2.wav"));
byte[] _1m = new byte[1024*1024];
int index = 0;
while (fileInputStream.read(_1m) != -1){
String path = "C:\\Users\\xin.chong\\Desktop\\aispeech-aichat\\明月几时有2.wav" +"__"+ index ++;
new FileOutputStream(new File(path)).write(_1m);
}
fileInputStream.close();
}
总结:
文件的合并注意点比较多,但是切分没太多注意事项,因为那是前端的事情,只要不影响测试就好
作者:香菜_香菜
链接:https://juejin.cn/post/7110938592944275486
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 点赞
- 收藏
- 关注作者
评论(0)