大家好,我是站长 polarisxu。上次介绍了标准库中的文件类型检测方法,有不少人提到它很不准。的确如此。本期介绍一个更好、更准的第三方库。

filetype(https://github.com/h2non/filetype)是一个 Go 语言的第三方库,可以根据文件的魔数(magic numbers)签名来推断文件的类型和 MIME 类型。它支持多种常见的文件类型,包括图片、视频、音频、文档、压缩包等。它还提供了一些便捷的函数和类型匹配器,可以方便地对文件进行分类和筛选。它的特点有:

  • 支持多种文件类型,提供文件扩展名和正确的 MIME 类型
  • 可以根据扩展名或 MIME 类型来发现文件类型
  • 可以根据类别(图片、视频、音频等)来发现文件类型
  • 可以添加自定义的新类型和匹配器
  • 简单而语义化的 API
  • 即使处理大文件也非常快速
  • 只需要前 262 字节表示最大的文件头,所以你可以只传递一个切片
  • 无依赖(只有 Go 代码,不需要 C 编译)
  • 跨平台的文件识别

实现原理分析

FF D8 FF89 50 4E 4750 4B 03 04
Matchertype Matcher func([]byte) boolMatchermatchers.Map
filetype.Match(buf)MatcherTypeUnknown
Typesmatchers.Map
IsImage(buf)IsVideo(buf)IsAudio(buf)MatchersIsImage(buf)image/
IsSupported(ext)IsMIMESupported(mime)GetType(ext)GetMIME(ext)types.goTypesIsSupported(ext)Types

使用示例

下面给出一些使用 filetype 库的具体例子:

简单地检测文件类型

输出:

File type: jpg. MIME: image/jpeg

检查文件类别

输出:

File is an image

查询支持的类型

输出:

Extension supported
MIME type supported

添加自定义类型和匹配器

输出:

New supported type: foo
New supported MIME type: foo/foo
File type matched: foo

优缺点分析,和标准库 http.DetectContentType 的对比

filetype 库相比于标准库中提供的 http.DetectContentType 函数有以下优缺点:

优点:

image/jpegimage/jpg

缺点:

  • 需要额外引入这个第三方库,并保持更新。
  • 可能存在一些未知或不常见格式的检测不准确或不支持的情况(但比标准库的好很多)

性能分析

filetype_test.go
go test -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: test/filetype
BenchmarkMatch-8        268744659                4.381 ns/op           0 B/op          0 allocs/op
BenchmarkDetect-8        8401593               142.1 ns/op             0 B/op          0 allocs/op
PASS
ok      test/filetype   3.478s

从输出中我们可以看到,filetype 的性能远高于标准库。(可能和标准库读取前 512 字节有关,而 filetype 只需要读取前 262 个字节)

综上所述,我们可以得出以下结论:

  • filetype 库是一个快速、无依赖的 Go 语言文件类型检测库,它支持多种常见的文件类型,并提供了一些便捷和灵活的函数和接口。
  • filetype 库的实现原理是基于文件的魔数(magic numbers)签名来进行类型检测的,它只需要前 262 字节表示最大的文件头,所以它可以只传递一个切片,不需要全部内容。
  • filetype 库的性能非常高,即使处理大文件也不会有明显的延迟。