记录一个很蠢的比较器问题

前几天写了一篇博客几种排序的不同写法 和 遍历列表的另外形式,但是在实际应用中还是犯了错误,就跟梗图里面表达的意思简直一样。
刚写完就出错,实在是有点尴尬。在这里插入图片描述


场景:正在做一个视频文件上传的模块,前端点击上传后传到后端,有四个步骤。

  1. 文件上传前的准备工作,校验文件是否存在;
  2. 检查分块文件是否存在;
  3. 上传分块;
  4. 合并分块。

功能完成后点击上传,发现分块目录、分块文件和合并文件都成功完成生成,但是前端就是显示上传失败!
通过断点调试发现,问题就出在第三步,合并分块后,对合并文件和原文件的Md5值的校验上。合并后的文件和原文件的Md5值不一样! 虽然两个文件的大小一模一样,但是Md5不一样就说明两个文件的内容已经改变了。此时再看合并文件,发现不能打开!

省略中间漫长的查找BUG过程,直接说结果。上一段代码吧。

private File mergeFile(List<File> chunkFileList, File mergeFile) {

		// 对块文件进行排序
		chunkFileList.sort(Comparator.comparing(File::getName));

		// 创建一个写对象
		try (RandomAccessFile raf_write = new RandomAccessFile(mergeFile, "rw")) {
			byte[] b = new byte[1024];
			for (File chunkFile : chunkFileList) {
				// 创建一个读对象
				try (RandomAccessFile raf_read = new RandomAccessFile(chunkFile, "r")) {
					int len = -1;
					while ((len = raf_read.read(b)) != -1) {
						raf_write.write(b, 0, len);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		return mergeFile;
	}

注意这一段代码:

chunkFileList.sort(Comparator.comparing(File::getName));

最终定位,问题就是这一段代码。方法引用表达式里面,getName返回的是String类型的文件名,这里的比较器比较的是String类型的name。而根据自己生成分块的逻辑,是以int类型的0开头,从大到小的分块名。下面进行一下这一段的测试。

	@Test
	public void test11() {
		// 分块文件夹路径
		String chunkFileFolderPath = "E:\\webs_workspace\\video\\3\\d\\3dcf73efe37de6608e3a2c48b8f6fbe1\\chunks\\";
		// 分块文件夹
		File chunkFileFolder = new File(chunkFileFolderPath);
		File[] files = chunkFileFolder.listFiles();
		assert files != null;
		List<File> fileList = Arrays.asList(files);
		fileList.sort(Comparator.comparing(File::getName));

		fileList.forEach(System.out::println);
	}

控制台输出:

E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\0
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\1
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\10
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\11
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\12
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\13
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\14
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\15
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\16
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\17
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\18
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\19
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\2
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\20
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\21
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\22
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\23
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\24
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\25
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\26
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\27
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\28
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\29
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\3
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\4
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\5
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\6
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\7
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\8
E:\webs_workspace\video\3\d\3dcf73efe37de6608e3a2c48b8f6fbe1\chunks\9
进程已结束,退出代码0

现在显而易见,chunkFileList.sort(Comparator.comparing(File::getName));这一段,在比较name字段时,是将其作为字符串比较的。先比较第一个字节,然后比较第二个,以此类推。所以就会出现上面那个数完1后直接开始10,19数完了数2的奇怪局面。当然,排序没排好就会导致分块列表不正确,进而导致块文件合并顺序与分割顺序不一致。

最后是解决,换成了λ表达式就可以了。

// 对块文件进行排序
chunkFileList.sort((o1, o2) -> {
	return Integer.parseInt(o1.getName()) > Integer.parseInt(o2.getName()) ? 1 : -1;
});

也尝试过用方法引用表达式来完成,但是没有找到很好的办法将name转为int类型。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值