Flutter for OpenHarmony 文件转换助手App实战 - Hash计算
UI 的状态管理(输入/输出、算法选择、加载态)文本与文件两种数据源(同一套 Hash 逻辑复用)大文件的性能(流式计算,避免内存峰值)最近一次计算记录:方便重复对比结果格式化:比如分组显示、大小写切换欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net。

Hash 计算用得最多的两个场景:
- 校验文件是否被篡改/传输是否完整(对比 Hash 值)
- 生成稳定的内容指纹(比如缓存 Key、去重标识)
这一节我用“文件转换助手”里的一个小工具页为例,把 Hash 计算做成一个可用的功能:
- 支持文本 Hash(直接输入)
- 支持文件 Hash(选择文件后计算)
- 支持多种算法(MD5 / SHA1 / SHA256 / SHA512)
- 结果可复制(方便粘贴到聊天/工单/脚本里)
Hash计算工具的应用
Hash计算在多个领域都有广泛应用。在文件传输中,我们可以通过比较Hash值来验证文件的完整性。在密码存储中,Hash算法用于保护用户密码的安全。
依赖准备
项目里我用的是 crypto 做 Hash 计算,文件选择和复制分别用常见的 file_picker 和 Clipboard(你可以按实际工程替换成更贴合 OpenHarmony 的能力)。
dependencies:
crypto: ^3.0.3
file_picker: ^6.1.1
上面只放了关键依赖,版本号不一定要一模一样;重点是 crypto 提供了 md5/sha256 等实现,后面做“流式计算”也靠它。
在工具页面中,Hash计算工具已经定义在工具列表中:
{'icon': Icons.fingerprint, 'title': 'Hash计算'},
这里我把它当作一个“工具入口配置”。真实项目里一般还会配一个 onTap 或路由名,方便点击后进入对应功能。
ListTile(
leading: const Icon(Icons.fingerprint),
title: const Text('Hash计算'),
onTap: () => _openHashTool(context),
)
我习惯把跳转/弹窗入口独立成一个方法(比如 _openHashTool),这样工具列表本身保持干净,后面做权限判断、埋点、参数透传也更好维护。
Hash计算对话框的实现
当用户点击Hash计算工具时,会显示一个对话框。这个对话框提供了输入和输出的界面:
void _openHashTool(BuildContext context) {
showDialog<void>(
context: context,
builder: (_) => const _HashDialog(),
);
}
这一段只负责“打开对话框”。具体 UI 和业务我放进 _HashDialog 里,避免一个函数越写越长(工具页一般会越做越复杂)。
class _HashDialog extends StatefulWidget {
const _HashDialog();
State<_HashDialog> createState() => _HashDialogState();
}
用 StatefulWidget 是因为这里一定会有状态:输入内容、算法选择、结果字符串、计算中 loading 等。
class _HashDialogState extends State<_HashDialog> {
final _inputController = TextEditingController();
final _outputController = TextEditingController();
void dispose() {
_inputController.dispose();
_outputController.dispose();
super.dispose();
}
}
这里我用两个 TextEditingController:
- 输入框:用户打字,实时拿到字符串
- 输出框:只读,用来展示 Hash 结果(直接写 controller,避免每次 setState 触发重建导致光标跳动)
Hash算法的支持
Hash计算工具可以支持多种算法,包括MD5、SHA-1、SHA-256、SHA-512等。每种算法都有不同的特点和应用场景。
MD5是一种较为简单的算法,但已经不再推荐用于安全敏感的应用。SHA-1和SHA-256是更安全的选择,其中SHA-256是目前最常用的算法。SHA-512提供了更高的安全性。
Hash算法的实现
在Flutter中,我们可以使用crypto包提供的实现来进行Hash计算:
enum HashAlgo { md5, sha1, sha256, sha512 }
我会先把算法做成一个枚举,后面 UI(下拉选择)和计算逻辑都可以围绕它展开,不需要到处写字符串常量。
import 'package:crypto/crypto.dart';
Hash _toCryptoHash(HashAlgo algo) {
return switch (algo) {
HashAlgo.md5 => md5,
HashAlgo.sha1 => sha1,
HashAlgo.sha256 => sha256,
HashAlgo.sha512 => sha512,
};
}
这一步做的是“枚举 -> crypto 的 Hash 实现”的映射。后面不管算文本还是文件,都可以统一拿到一个 Hash 对象。
import 'dart:convert';
String hashText(String input, HashAlgo algo) {
final bytes = utf8.encode(input);
final digest = _toCryptoHash(algo).convert(bytes);
return digest.toString();
}
文本 Hash 很直接:
- 统一用 UTF-8 编码,避免不同平台/不同输入法导致结果不一致
- 返回值是十六进制字符串,拿去对比或复制都方便
文本和文件的Hash计算
Hash计算工具可以支持两种输入模式:文本和文件。对于文本输入,用户直接在输入框中输入内容。对于文件输入,用户可以选择一个文件,系统会计算该文件的Hash值。
import 'package:file_picker/file_picker.dart';
import 'dart:io';
Future<File?> pickOneFile() async {
final result = await FilePicker.platform.pickFiles();
final path = result?.files.single.path;
return path == null ? null : File(path);
}
文件选择这里不纠结“选什么格式”,直接让用户选一个文件。真实项目里我通常会加:
- 允许的后缀过滤(避免用户选到不该处理的文件)
- 空结果处理(用户点了取消)
大文件的Hash计算
对于大文件,我们需要使用流式读取来避免一次性将整个文件加载到内存中。
import 'package:crypto/crypto.dart';
import 'dart:io';
Future<String> hashFile(File file, HashAlgo algo) async {
final out = AccumulatorSink<Digest>();
final sink = _toCryptoHash(algo).startChunkedConversion(out);
await for (final chunk in file.openRead()) {
sink.add(chunk);
}
sink.close();
return out.events.single.toString();
}
这里的关键点是 chunked conversion:
- 不会把整个文件读进内存,对大文件更稳
openRead()默认就会按块读取,await for一边读一边喂给sink- 最终从
AccumulatorSink拿到Digest,再转成字符串
Hash结果的处理
计算得到的Hash值是一个长的十六进制字符串。用户可以复制这个结果到剪贴板,或者保存到文件中。
import 'package:flutter/services.dart';
Future<void> copyToClipboard(BuildContext context, String text) async {
await Clipboard.setData(ClipboardData(text: text));
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已复制到剪贴板')),
);
}
我这里做了两件小事:
- 复制成功给一个反馈,用户不会怀疑“到底有没有复制上”
context.mounted是为了防止异步完成时页面已经关闭导致异常
void runTextHash() {
final input = _inputController.text.trim();
if (input.isEmpty) return;
final result = hashText(input, HashAlgo.sha256);
_outputController.text = result;
}
执行按钮的处理我倾向于保持“短、直、可读”:
- 先做输入判空(空字符串算出来也有值,但对用户没意义)
- 默认算法可以先给
SHA-256,后续再加下拉框让用户切换
总结
Hash 工具看起来很小,但它会牵扯到几块很“项目化”的细节:
- UI 的状态管理(输入/输出、算法选择、加载态)
- 文本与文件两种数据源(同一套 Hash 逻辑复用)
- 大文件的性能(流式计算,避免内存峰值)
后续如果你打算把它做成一个更像“工具”的形态,我建议再补两点:
- 最近一次计算记录:方便重复对比
- 结果格式化:比如分组显示、大小写切换
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)