Flutter 对字符串,文件MD5

3,484 阅读2分钟

几句唠叨

在日常开发过程中,经常需要对字符串或文件进行md5。 话不多说,下面我们一步一步来看,会发现原来在Flutter中简单的md5也有蛮多小细节。

准备

在项目中加入crypto第三方库

crypto: ^3.0.2

Flutter对字符串进行md5

import 'package:crypto/crypto.dart';
import 'dart:convert';

final url = "target string";
final hash = md5.convert(utf8.encode(url)).toString();

Flutter对文件md5

Future<String> getFileHash(String filePath) async {
  final file = File(filePath);
  final fileLength = file.lengthSync();

  final fileBytes = file.readAsBytesSync().buffer.asUint8List();
  final hash = md5.convert(fileBytes.buffer.asUint8List()).toString();
  return hash;
}

好了,目前这样基本上符合一般需求了。但对于文件进行md5,上面的代码有一个很致命的问题!大文件都读取并加载的内存中进行md5计算,这样的话,很容易导致APP因为内存过大而闪退。所以我们继续!

Flutter对文件md5

对于大文件,假如我们以50M为基准,进行分布读取累加计算md5, 这样分段流式计算,既能正确无误的计算出大文件的md5,且可以防止内存突然升高。很完美!^_^

const int SIZE_50M = 50 * 1024 * 1024;

Future<String> getFileHash(String filePath) async {
  final file = File(filePath);
  final fileLength = file.lengthSync();

  final sFile = await file.open();
  try {
    final output = AccumulatorSink<Digest>();
    final input = md5.startChunkedConversion(output);
    int x = 0;
    const chunkSize = SIZE_50M;
    while (x < fileLength) {
      final tmpLen = fileLength - x > chunkSize ? chunkSize : fileLength - x;
      input.add(sFile.readSync(tmpLen));
      x += tmpLen;
    }
    input.close();

    final hash = output.events.single;
    return hash.toString();
  } finally {
    unawaited(sFile.close());
  }
}

到此, 在Flutter中,针对大文件md5也解决了。这样使用固然没有错。但是还是有一个很大的问题,就是慢,真的慢!毕竟计算是在dart vm虚拟机上跑。

经过笔者测试,针对稍大的文件进行MD5,发现原生系统MD5比使用flutter crypto提供的MD5快了差不多10倍

既然这样,就好办了,写一个Flutter Plugin就行了!把需要md5文件的路径传递到原生系统,原生计算完结果返回就行了。

是的,大家没有猜错,代码点击直接可取。实现细节没什么好说的。

还是简单说一下如何在Flutter项目使用

  1. 引入
  fb_utils:
    git:
      url: https://github.com/zingwin/fb_utils
      ref: 0b41cb5faabfbd4d579b837e83a0683a25eb2de8
  1. 使用
import 'package:fb_utils/fb_utils.dart';


final hash = FbUtils.getMD5WithPath(file.filePath);