(原) 有什么方法能够获取文件类型?

原创文章,请后转载,并注明出处。

Windows是通过扩展名来判断文件类型的,这是一个很傻很天真的认识。我想知道的是它真实的文件类型。

看起来一般文件在文件头是有类型标识的,但通过实际的测试,这种标识也不是很明确。

package main

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"strconv"
	"strings"
	"sync"
)

var fileTypeMap sync.Map

func init() {
	fileTypeMap.Store("ffd8ffe000104a464946", "jpg")  //JPEG (jpg)
	fileTypeMap.Store("ffd8ffdb008400060405", "jpg")  // JPEG
	fileTypeMap.Store("89504e470d0a1a0a0000", "png")  // PNG (png)
	fileTypeMap.Store("474946383961", "gif")          // GIF (gif)
	fileTypeMap.Store("49492a00227105008037", "tif")  //TIFF (tif)
	fileTypeMap.Store("424d228c010000000000", "bmp")  //16色位图(bmp)
	fileTypeMap.Store("424d8240090000000000", "bmp")  //24位位图(bmp)
	fileTypeMap.Store("424d8e1b030000000000", "bmp")  //256色位图(bmp)
	fileTypeMap.Store("41433130313500000000", "dwg")  //CAD (dwg)
	fileTypeMap.Store("3c21444f435459504520", "html") //HTML (html)   3c68746d6c3e0  3c68746d6c3e0
	fileTypeMap.Store("3c68746d6c3e0", "html")        //HTML (html)   3c68746d6c3e0  3c68746d6c3e0
	fileTypeMap.Store("3c21646f637479706520", "htm")  //HTM (htm)
	fileTypeMap.Store("48544d4c207b0d0a0942", "css")  //css
	fileTypeMap.Store("696b2e71623d696b2e71", "js")   //js
	fileTypeMap.Store("7b5c727466315c616e73", "rtf")  //Rich Text Format (rtf)
	fileTypeMap.Store("38425053000100000000", "psd")  //Photoshop (psd)
	fileTypeMap.Store("46726f6d3a203d3f6762", "eml")  //Email [Outlook Express 6] (eml)
	fileTypeMap.Store("d0cf11e0a1b11ae10000", "doc")  //MS Excel 注意:word、msi 和 excel的文件头一样
	fileTypeMap.Store("d0cf11e0a1b11ae10000", "vsd")  //Visio 绘图
	fileTypeMap.Store("5374616E64617264204A", "mdb")  //MS Access (mdb)
	fileTypeMap.Store("252150532D41646F6265", "ps")
	fileTypeMap.Store("255044462d312e3", "pdf")       // Adobe Acrobat (pdf)
	fileTypeMap.Store("2e524d46000000120001", "rmvb") //rmvb/rm相同
	fileTypeMap.Store("464c5601050000000900", "flv")  //flv与f4v相同
	fileTypeMap.Store("00000020667479706d70", "mp4")
	fileTypeMap.Store("49443303000000002176", "mp3")
	fileTypeMap.Store("000001ba210001000180", "mpg") //
	fileTypeMap.Store("3026b2758e66cf11a6d9", "wmv") //wmv与asf相同
	fileTypeMap.Store("52494646e27807005741", "wav") //Wave (wav)
	fileTypeMap.Store("52494646d07d60074156", "avi")
	fileTypeMap.Store("4d546864000000060001", "mid") //MIDI (mid)
	fileTypeMap.Store("504b0304140000000800", "zip")
	// 这都是zip压缩文件,与jar还要重合
        //                 504b0304140000080800
	//                 504b0304140000000800
	//                 504b0304140000080800
	//		   504b0304140000080800
	//                 504b03040a0000000000
	//                 504b0304140000080800
	fileTypeMap.Store("526172211a0700cf9073", "rar")
	fileTypeMap.Store("235468697320636f6e66", "ini")
	fileTypeMap.Store("504b03040a0000000000", "jar")
	fileTypeMap.Store("4d5a9000030000000400", "exe")  //可执行文件
	fileTypeMap.Store("3c25402070616765206c", "jsp")  //jsp文件
	fileTypeMap.Store("4d616e69666573742d56", "mf")   //MF文件
	fileTypeMap.Store("3c3f786d6c2076657273", "xml")  //xml文件
	fileTypeMap.Store("494e5345525420494e54", "sql")  //xml文件
	fileTypeMap.Store("7061636b616765207765", "java") //java文件
	fileTypeMap.Store("406563686f206f66660d", "bat")  //bat文件
	fileTypeMap.Store("1f8b0800000000000000", "gz")   //gz文件
	//1f8b08001a5dcf5d0003
	fileTypeMap.Store("6c6f67346a2e726f6f74", "properties") //bat文件
	fileTypeMap.Store("cafebabe0000002e0041", "class")      //bat文件
	fileTypeMap.Store("49545346030000006000", "chm")        //bat文件
	fileTypeMap.Store("04000000010000001300", "mxp")        //bat文件
	fileTypeMap.Store("504b0304140006000800", "docx")       //docx文件
	fileTypeMap.Store("504b0304140008080800", "xlsx")       // xlsx文件
	fileTypeMap.Store("d0cf11e0a1b11ae10000", "wps")        //WPS文字wps、表格et、演示dps都是一样的
	fileTypeMap.Store("6431303a637265617465", "torrent")    //
	fileTypeMap.Store("6D6F6F76", "mov")                    //Quicktime (mov)
	fileTypeMap.Store("FF575043", "wpd")                    //WordPerfect (wpd)
	fileTypeMap.Store("CFAD12FEC5FD746F", "dbx")            //Outlook Express (dbx)
	fileTypeMap.Store("2142444E", "pst")                    //Outlook (pst)
	fileTypeMap.Store("AC9EBD8F", "qdf")                    //Quicken (qdf)
	fileTypeMap.Store("E3828596", "pwl")                    //Windows Password (pwl)
	fileTypeMap.Store("2E7261FD", "ram")                    //Real Audio (ram)
	fileTypeMap.Store("504b0304", "xmind/apk")              // xmind 或 安卓程序
	fileTypeMap.Store("377abcaf271c000", "7z")              // 7z压缩文件
	// 504b03040a0000000800 .sb3  Scratch3.0
	// txt文本文件没有任何头部标识
}

// 获取前面结果字节的二进制
func bytesToHexString(src []byte) string {
	res := bytes.Buffer{}
	if src == nil || len(src) <= 0 {
		return ""
	}
	temp := make([]byte, 0)
	for _, v := range src {
		sub := v & 0xFF
		hv := hex.EncodeToString(append(temp, sub))
		if len(hv) < 2 {
			res.WriteString(strconv.FormatInt(int64(0), 10))
		}
		res.WriteString(hv)
	}
	return res.String()
}

// 用文件前面几个字节来判断
// fSrc: 文件字节流(就用前面几个字节)
func GetFileType(fSrc []byte) string {
	var fileType string
	var tempSave string // 临时用来保存可能的类型
	fileCode := bytesToHexString(fSrc)

	fmt.Println(fileCode, "----")
	fileTypeMap.Range(func(key, value interface{}) bool {
		k := strings.ToLower(key.(string))
		v := value.(string)
		if strings.HasPrefix(fileCode, k) {
			// 保存Key,保留最长的。即优先匹配长串

			if len(tempSave) < len(k) {
				fileType = v
				tempSave = k
			}
		}
		return true
	})
	return fileType
}

func main(){
	f, _ := os.Open("c:/tools/rufus_3.16p_Single.zip")
	fSrc, _ := ioutil.ReadAll(f)
	fmt.Println(GetFileType(fSrc[:10]))
}

最终,不能绝对确认文件类型。也不知道linux中的类型是如何判断的。