Flutter中选取无扩展名文件时如何获取其MIME类型?
核心实现思路
仅依赖文件名后缀判断MIME类型本身就不可靠,无后缀场景下必须通过读取文件头部的*魔数(Magic Number)*特征来匹配对应类型,这是所有场景下通用的准确判断方案。
前端Web环境
浏览器原生File API的File.type属性部分场景下会依赖后缀,无后缀时可以自己读取文件头判断:
// 定义常见文件类型的魔数匹配规则,按需补充业务需要覆盖的类型 const mimeMagicRules = [ { mime: 'image/jpeg', magic: [0xFF, 0xD8, 0xFF] }, { mime: 'image/png', magic: [0x89, 0x50, 0x4E, 0x47] }, { mime: 'application/pdf', magic: [0x25, 0x50, 0x44, 0x46] }, { mime: 'application/zip', magic: [0x50, 0x4B, 0x03, 0x04] } ] async function getFileMime(file) { // 原生返回的类型非空可以直接复用 if (file.type) return file.type // 读取文件前8字节,大部分类型的魔数都在这个范围内 const arrBuffer = await file.slice(0, 8).arrayBuffer() const headerBytes = new Uint8Array(arrBuffer) // 规则匹配 for (const rule of mimeMagicRules) { const isMatch = rule.magic.every((byte, index) => headerBytes[index] === byte) if (isMatch) return rule.mime } // 未匹配到返回通用二进制类型 return 'application/octet-stream' }
直接把file picker返回的File对象传入上述方法即可拿到对应MIME类型。
Android原生环境
不要使用完全依赖扩展名判断的MimeTypeMap类,优先通过内容解析器获取系统返回的类型,为空时再自行匹配魔数:
fun getMimeTypeFromUri(context: Context, uri: Uri): String { // 先取ContentResolver返回的系统识别类型 val resolverType = context.contentResolver.getType(uri) if (resolverType != null) return resolverType // 系统识别为空时读取文件头匹配魔数 context.contentResolver.openInputStream(uri)?.use { input -> val header = ByteArray(8) input.read(header) val customMatchResult = matchMagicToMime(header) if (customMatchResult != null) return customMatchResult } return "application/octet-stream" }
其中matchMagicToMime方法的魔数匹配逻辑和前端实现一致。
iOS原生环境
UIDocumentPickerViewController返回的文件URL可以先通过UTI转换为MIME类型,无后缀也可正常识别,识别失败再匹配魔数:
func getMimeType(for url: URL) -> String { // 优先通过UTI转换MIME if let uti = try? url.resourceValues(forKeys: [.typeIdentifierKey]).typeIdentifier, let mime = UTTypeCopyPreferredTagWithClass(uti as CFString, kUTTagClassMIMEType)?.takeRetainedValue() as? String { return mime } // 识别失败读取文件头匹配魔数 if let handle = try? FileHandle(forReadingFrom: url) { let header = handle.readData(ofLength: 8) if let customMatchResult = matchMagicToMime(header) { return customMatchResult } } return "application/octet-stream" }
注意:魔数规则不需要全量覆盖所有文件类型,只需要补充你的业务场景需要支持的类型即可,降低匹配开销。普通场景下优先用各平台原生API返回的类型,已经能覆盖90%以上的日常使用需求,性能也更高。
内容的提问来源于stack exchange,提问作者Maheswari
相关产品推荐
相关产品推荐

