最新要闻

广告

手机

防汛一线显担当丨风雨砺初心 防汛急先锋

防汛一线显担当丨风雨砺初心 防汛急先锋

问河北|出了家门就进公园,河北咋实现?

问河北|出了家门就进公园,河北咋实现?

家电

大文件 MD5 SHA 校验时间优化之路

来源:博客园

最近研发apk校验服务,很多游戏安装包两三个G,如果整个拿去校验,耗时基本二十多秒,这还仅仅是校验的时间,如果加上下载的时间,等待时间太长了

网上很多方案尝试了一下,不太行

1、fast md5


(资料图片仅供参考)

一个第三方库,csdn有人用过说可以提升40%的速度,然后我去试了一下,本来9秒可以完成的校验,变成了2分多钟,我真是口吐莲花

2、把MD5替换成SHA算法

提升不明显,哪怕从30秒缩短到20几秒,依然接受不了

所以只能寻求其它方案了

分片校验法

很多上传下载大文件,会采用分片的方法去做,这样就可以开启多个任务对同一个文件进行操作,速度提升好几倍

如法炮制,先写个demo尝试一下,看看是否可行

先把文件进行分片,找个几百M的apk测试一下

private fun verifySpilt() {        filesDir?.let { path ->            val it = File(path.absolutePath + "/test.apk")            tvContent?.text = "${path.absolutePath}/test.apk"            val inputStream = FileInputStream(it)            var out: FileOutputStream? = null            val inChannel = inputStream.channel            var outChannel: FileChannel? = null            val m = (10 * 1024 * 1024).toLong()            // 分片数量            val count = (it.length() / m).toInt()            Log.e("--==", "count $count")            for (i in 0..count) {                // 生成文件的路径                val tPath = "${path.absolutePath}/test_$i"                val toFile = File(tPath)                if (toFile.exists()) {                    toFile.mkdir()                }                Log.e("--==", "to path $tPath")                try {                    out = FileOutputStream(toFile)                    outChannel = out.channel                    // 从inChannel的m*i处,读取固定长度的数据,写入outChannel                    if (i != count) inChannel.transferTo(                        m * i,                        m,                        outChannel                    ) else {                        // 最后一个文件                        inChannel.transferTo(m * i, it.length() - m * count, outChannel)                    }                } catch (e: IOException) {                    Log.e("--==", "IOException $e")                    return                } finally {                    out?.close()                    outChannel?.close()                    Log.e("--==", "finally close")                }            }            inputStream.close()            inChannel.close()        }    }

对 test.apk 进行分片校验

直接在 demo 工程里面 main方法调用

得到了十来个片段文件

接下来写个校验方法,对其中的片段文件校验,比如分片后,删了这些片段文件在重新生成,md5值是否一致

private fun verify(position: Int) {        filesDir?.let { path ->            val it = File(path.absolutePath + "/test1_$position")            val digest = MessageDigest.getInstance("MD5")            val fis = FileInputStream(it)            val channel = fis.channel            val byteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, it.length())            digest.update(byteBuffer)            val bytes = digest.digest()            tvContent?.text = bytes2HexString(bytes)            Log.e("--==", "${bytes2HexString(bytes)}")        }    }

打印的日志发现一致,说明只要切片的方式一样,是可以进行校验的

然后我改了分片的逻辑,每个片段大小调整了一下,得到5个片段,此时结果肯定就不一致了

其实到这里已经算成型了,居然分片可行,那么一个大文件直接分成10份,同时验证,然后对比结果,速度可不止快了一倍

后面是无聊尝试的结果,肯定是没问题的,否则就要考虑代码的问题了

找个视频加一个新建的text文本,文本里面输入111,然后压缩,得到 test1 的压缩包

然后修改文本变成1111,在压缩,得到 test2 压缩包,在赋值 test1 压缩包 得到 test1_copy 压缩包,一共三个文件

把文件复制到内存目录中测试

结果没问题,毕竟是整个文件直接校验

关键词: