您当前的位置:首页 > 计算机 > 编程开发 > Java

通过NIO分割文件和合并文件和计算文件md5

时间:02-08来源:作者:点击数:

最新补充:发现把文件映射为MapedByteBuffer后,即使输入流关闭,通道关闭,它还是引用着文件句柄,这样我们无法删除文件或者重命名,网上有一些解决方法,但是不推荐使用,必竟不是官方出来的方法,所以在官方解决这个问题之前,还是使用普通的方式吧,如下:

object FileUtil {

    /** 获取文件md5(异步方式) */
    fun getFileMd5(file: File, callback: (String) -> Unit) {
        thread {
            val fileMd5 = getFileMd5(file)
            callback(fileMd5)
        }
    }

    /** 获取文件md5(同步方式) */
    fun getFileMd5(file: File): String {
        val messageDigest = MessageDigest.getInstance("MD5")
        FileInputStream(file).use { fis ->
            val buf = ByteArray(8192)
            var length: Int
            while (fis.read(buf, 0, 8192).also { length = it } != -1) {
                messageDigest.update(buf, 0, length)
            }
        }

        // 获取md5签名(16个字节)
        val md5Bytes = messageDigest.digest()

        // 将byte数组的签名转换为16进制的字符串
        val bigInteger = BigInteger(1, md5Bytes) // 把16个字节当成一个无符号的大整数
        var md5String = bigInteger.toString(16)    // 把大整数转换为16进制的字符串形式
        repeat(32 - md5String.length) { // 预防字符串不够32位。1个byte需要两位16进制数,而md5Bytes的长度为16,所以需要32位的16进制数来表示。
            md5String = "0$md5String"
        }
        return md5String
    }

}

NIO就是香啊,不但效率高,而且写起来代码也少(注:下面获取md5的代码不要采用,有Bug),示例如下:

object FileUtil {

    fun getFileMd5(file: File): String {
        // 获取md5签名
        val md5Bytes = FileInputStream(file).channel.use { channel ->
            val byteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size())
            MessageDigest.getInstance("MD5").run {
                update(byteBuffer)
                digest()
            }
        }

        // 将签名转换为16进制的字符串
        val bigInteger = BigInteger(1, md5Bytes) // 把16个字节当成一个无符号的大整数
        var md5String = bigInteger.toString(16)    // 把大整数转换为16进制的字符串形式
        repeat(32 - md5String.length) { // 预防字符串不够32位。1个byte需要两位16进制数,而md5Bytes的长度为16,所以需要32位的16进制数来表示。
            md5String = "0$md5String"
        }
        return md5String
    }

    fun splitFile(file: File, splitCount: Int): MutableList<File> {
        val splitFiles = mutableListOf<File>()
        val fileLength = file.length()
        val avgSize = fileLength / splitCount
        val lastPartSize = fileLength - avgSize * (splitCount - 1)
        FileInputStream(file).channel.use { wavChannel ->
            for (i in 0 until splitCount) {
                val splitFile = File("${file.absolutePath}.$i")
                splitFiles.add(splitFile)
                FileOutputStream(splitFile).channel.use {
                    val position = i * avgSize
                    val count = if (i == splitCount - 1) lastPartSize else avgSize
                    wavChannel.transferTo(position, count, it)
                }
            }
        }
        return splitFiles
    }

    fun mergeFiles(files: List<File>, targetFile: File) {
       FileOutputStream(targetFile, true).channel.use { targetChannel ->
           files.forEach { file ->
               FileInputStream(file).channel.use { sourceChannel ->
                   targetChannel.transferFrom(sourceChannel, targetChannel.size(), sourceChannel.size())
               }
           }
       }
    }

}
fun main() {
    var start = System.currentTimeMillis()
    val sourceFile = File("D:\\功夫.HD720高清国语中字版.mp4")
    val splitCount = 3
    val fileMd5 = FileUtil.getFileMd5(sourceFile)
    println("计算原文件md5 = $fileMd5, 所花时间:${System.currentTimeMillis() - start}")

    start = System.currentTimeMillis()
    val files = FileUtil.splitFile(sourceFile, splitCount)
    println("文件分割完成,所花时间:${System.currentTimeMillis() - start}")

    start = System.currentTimeMillis()
    val newFile = File("D:\\haha.mp4")
    FileUtil.mergeFiles(files, newFile)
    println("文件合并完成,所花时间:${System.currentTimeMillis() - start}")

    start = System.currentTimeMillis()
    val newFileMd5 = FileUtil.getFileMd5(newFile)
    println("计算新文件md5 = $newFileMd5, 所花时间:${System.currentTimeMillis() - start}")
}

运行结果如下:

计算原文件md5 = 870257cd37f47a81d528e5c871dc3901, 所花时间:3981
文件分割完成,所花时间:615
文件合并完成,所花时间:2610
计算新文件md5 = 870257cd37f47a81d528e5c871dc3901, 所花时间:3711

分割与合并的文件如下:

在这里插入图片描述

功夫.HD720高清国语中字版.mp4是一个1.03G的视频文件,分割成了3个,然后又合并为1个。从打印的结果来看,计算md5是比较耗时的,比文件分割和合并都慢。而合并文件比分割文件要慢很多,这个是什么原理我也不是很清楚。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门