中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang基于文件魔數如何判斷文件類型

發布時間:2023-02-20 09:49:02 來源:億速云 閱讀:106 作者:iii 欄目:開發技術

本篇內容介紹了“Golang基于文件魔數如何判斷文件類型”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

查找位置

File.Seek()函數可以設置偏移位置,為下一次讀或寫確定偏移量,具體起點有whence確定:0標識相對文件開始位置、1相對當前位置、2相對文件結尾。函數返回新的位置及錯誤。請看下面示例:

package main
 
import (
   "os"
   "fmt"
   "log"
)
 
func main() {
   file, _ :- os.Open("test.txt")
   defer file.Close()
 
   // Offset 表示偏移量
   // Offset 可以為正數或負數
   var offset int64 - 5
 
   // Whence 偏移參考點,具體取值說明
   // 0 - Beginning of file
   // 1 - Current position
   // 2 - End of file
   var whence int - 0
   newPosition, err :- file.Seek(offset, whence)
   if err !- nil {
      log.Fatal(err)
   }
   fmt.Println("Just moved to 5:", newPosition)
 
   // 從當前位置回走2個字節
   newPosition, err - file.Seek(-2, 1)
   if err !- nil {
      log.Fatal(err)
   }
   fmt.Println("Just moved back two:", newPosition)
 
   // 通過移動零字節返回當前位置
   currentPosition, err :- file.Seek(0, 1)
   fmt.Println("Current position:", currentPosition)
 
   // 回到文件起始點
   newPosition, err - file.Seek(0, 0)
   if err !- nil {
      log.Fatal(err)
   }
   fmt.Println("Position after seeking 0,0:", newPosition)
}

執行程序結果如下:

Just moved to 5: 5
Just moved back two: 3
Current position: 3
Position after seeking 0,0: 0

文件類型

魔數是文件前幾個字節,用于唯一標識文件類型,從而無需關注復雜文件結構就能夠確定文件類型。舉例,jpeg文件總是ffd8 ffe0。下面列舉常見文件類型的魔數:

  • 圖像文件

File typeTypical extensionHex digits xx - variableAscii digits . - not an ascii char
Bitmap format.bmp42 4dBM
FITS format.fits53 49 4d 50 4c 45SIMPLE
GIF format.gif47 49 46 38GIF8
Graphics Kernel System.gks47 4b 53 4dGKSM
IRIS rgb format.rgb01 da…
ITC (CMU WM) format.itcf1 00 40 bb…
JPEG File Interchange Format.jpgff d8 ff e0…
NIFF (Navy TIFF).nif49 49 4e 31IIN1
PM format.pm56 49 45 57VIEW
PNG format.png89 50 4e 47.PNG
Postscript format.[e]ps25 21%!
Sun Rasterfile.ras59 a6 6a 95Y.j.
Targa format.tgaxx xx xx…
TIFF format (Motorola - big endian).tif4d 4d 00 2aMM.*
TIFF format (Intel - little endian).tif49 49 2a 00II*.
X11 Bitmap format.xbmxx xx
XCF Gimp file structure.xcf67 69 6d 70 20 78 63 66 20 76gimp xcf
Xfig format.fig23 46 49 47#FIG
XPM format.xpm2f 2a 20 58 50 4d 20 2a 2f/* XPM */
  • 壓縮文件類型

File typeTypical extensionHex digits xx = variableAscii digits . = not an ascii char
Bzip.bz42 5aBZ
Compress.Z1f 9d…
gzip format.gz1f 8b…
pkzip format.zip50 4b 03 04PK…
  • 歸檔文件類型

File typeTypical extensionHex digits xx = variableAscii digits . = not an ascii char
TAR (pre-POSIX).tarxx xx(a filename)
TAR (POSIX).tar75 73 74 61 72ustar (offset by 257 bytes)
  • 可執行文件類型

File typeTypical extensionHex digits xx = variableAscii digits . = not an ascii char
MS-DOS, OS/2 or MS Windows
4d 5aMZ
Unix elf
7f 45 4c 46.ELF

有了上面的基礎知識,我們就可以讀文件前幾個字節判斷文件類型。

實現基礎函數

首先定義文件魔數標識變量:

var(
   PDF        = []byte{0x25, 0x50, 0x44, 0x46}
	RAR        = []byte{0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00}
	GZIP       = []byte{0x1F, 0x8B, 0x08}
	ZIP_0      = []byte{0x50, 0x4B, 0x03, 0x04}
	ZIP_1      = []byte{0x50, 0x4B, 0x05, 0x06}
	ZIP_2      = []byte{0x50, 0x4B, 0x07, 0x08}
	WEBP       = []byte{0x52, 0x49, 0x46, 0x46}
   ...
)

下面定義幾個讀文件函數。

首先是從ReadSeeker開始位置起讀取幾個字節函數:

func readUntil(l int, r io.ReadSeeker) ([]byte, error) {
	buff := make([]byte, l)

	_, err := r.Read(buff)
	if err != nil {
		return nil, err
	}

	r.Seek(0, io.SeekStart)

	return buff, nil
}

基于魔數字節數組讀文件魔數:

func checkBuffer(r io.ReadSeeker, t []byte) ([]byte, error) {
   // 根據提供參數獲取長度
	l := len(t)

	buff, err := readUntil(l, r)
	if err != nil {
		return make([]byte, 0), err
	}

	return buff, nil
}

基于參數比較文件魔數:

func genericCompareBuffer(r io.ReadSeeker, t []byte) bool {
	buff, err := checkBuffer(r, t)
	if err != nil {
		return false
	}

	valid := bytes.Compare(t, buff)
	return valid == 0
}

比較文件包括多個魔數情況比較:

func genericMultipleCompareBuffer(r io.ReadSeeker, t [][]byte) bool {
	buff, err := checkBuffer(r, t[0])
	if err != nil {
		return false
	}

	for _, v := range t {
		if bytes.Compare(v, buff) == 0 {
			return true
		}
	}

	return false
}

類型判斷函數

有了上面的基礎函數,我們可以提供上層應用接口函數。

首先是常用類型判斷函數,注意這里PNG、JPEG是前面定義的字節數組變量。

// IsPng function will return true if File is a valid PNG
func IsPng(r io.ReadSeeker) bool {
	return genericCompareBuffer(r, PNG)
}

// IsJpeg function will return true if File is a valid JPEG
func IsJpeg(r io.ReadSeeker) bool {
	return genericCompareBuffer(r, JPEG)
}

// IsPdf function will return true if File is a valid PDF
func IsPdf(r io.ReadSeeker) bool {
	return genericCompareBuffer(r, PDF)
}

// IsGif function will return true if File is a valid GIF
func IsGif(r io.ReadSeeker) bool {
	return genericCompareBuffer(r, GIF)
}

同類文件可能有不同魔數場景:

// IsMpg function will return true if File is a valid MPG
func IsMpg(r io.ReadSeeker) bool {
	return genericMultipleCompareBuffer(r, [][]byte{
		MPG_0,
		MPG_1,
	})
}

最后提供一個同時判斷多種文件類型的函數,利用函數類型參數:

// IsOneOf function will validate File with multiple function
func IsOneOf(r io.ReadSeeker, functions ...function) bool {
	for _, f := range functions {
		valid := f(r)
		if valid {
			return true
		}
	}

	return false
}

測試代碼

下面測試前面定義的函數,函數包括文件名稱參數,判斷該文件類型:

package main

import (
	"fmt"
	"os"
)

func main() {
	args := os.Args

	if len(args) < 2 {
		fmt.Println("required input file")
		os.Exit(1)
	}

   // 打開文件
	inputFileArg := args[1]
	inFile, err := os.Open(inputFileArg)

	if err != nil {
		fmt.Println("error open input file ", err)
		os.Exit(1)
	}

   // 支持錯誤處理的關閉方式
	defer func() { 
      err := inFile.Close() 
      if err != nil {
         fmt.Println("error close input file ", err)
      }
   }()

   // 一次性判斷多種類型,如:是否為圖像文件
	valid := IsOneOf(inFile, filesig.Is3gp, filesig.IsPng, filesig.IsJpeg)
	fmt.Println(valid)

   // 當然也可以判斷單個類型
   valid = filesig.Is3gp(inFile)
	fmt.Println(valid)
}

“Golang基于文件魔數如何判斷文件類型”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

勃利县| 宾川县| 乡宁县| 黔东| 樟树市| 定襄县| 英吉沙县| 吉安县| 吐鲁番市| 都安| 三都| 石屏县| 江永县| 万州区| 顺昌县| 休宁县| 双流县| 清河县| 泰和县| 池州市| 浦城县| 华容县| 天等县| 三穗县| 郁南县| 东乡县| 大洼县| 西青区| 昌吉市| 芒康县| 尉氏县| 永清县| 临高县| 锦屏县| 哈尔滨市| 屯门区| 冀州市| 隆安县| 新宁县| 海宁市| 万宁市|