Golang 源码解析 DetectContentType 检测文件类型

我们可以使用 golang 中的 net/http 包的来查找文件的内容类型或 mime 类型。

DetectContentType 函数实现了 http://mimesniff.spec.whatwg.org/ 描述的算法,用于确定数据的 Content-Type .

该函数会检查数据的前 512 字节,然后返回一个合法的 MIME 类型,例如 application/json 或类似 image/jpg .

如果不能确定数据的类型,将返回 "application/octet-stream" .

为此,我们打开文件并读取前512个字节,

package main

import (
    "os"
    "fmt"
    "net/http"
)

func main() {

    // Open File
    f, err := os.Open("test.pdf")
    if err != nil {
        panic(err)
    }
    defer f.Close()

    // Get the content
    contentType, err := GetFileContentType(f)
    if err != nil {
        panic(err)
    }

    fmt.Println("Content Type: " + contentType)
}

func GetFileContentType(out *os.File) (string, error) {

    // 仅使用前512个字节来检测内容类型。
    buffer := make([]byte, 512)

    _, err := out.Read(buffer)
    if err != nil {
        return "", err
    }

    // 使用 net/http 包中的的DectectContentType函数,它将始终返回有效的 MIME 类型
    // 对于没有匹配的未知类型,将返回 "application/octet-stream"
    contentType := http.DetectContentType(buffer)

    return contentType, nil
}

DetectContentType 函数源码

package http

import (
    "bytes"
    "encoding/binary"
)

// The algorithm uses at most sniffLen bytes to make its decision.
const sniffLen = 512

// DetectContentType implements the algorithm described
// at https://mimesniff.spec.whatwg.org/ to determine the
// Content-Type of the given data. It considers at most the
// first 512 bytes of data. DetectContentType always returns
// a valid MIME type: if it cannot determine a more specific one, it
// returns "application/octet-stream".
func DetectContentType(data []byte) string {
    if len(data) > sniffLen {
        data = data[:sniffLen]
    }

    // Index of the first non-whitespace byte in data.
    firstNonWS := 0
    for ; firstNonWS < len(data) && isWS(data[firstNonWS]); firstNonWS++ {
    }

    for _, sig := range sniffSignatures {
        if ct := sig.match(data, firstNonWS); ct != "" {
            return ct
        }
    }

    return "application/octet-stream" // fallback
}

源码链接:https://github.com/golang/go/blob/master/src/net/http/sniff.go#L21

标签: golang, mime, ContentType, 源码