star/mime/mime.go
2025-06-13 13:05:50 +08:00

155 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package mime
import (
"b612.me/starlog"
"b612.me/staros"
"encoding/csv"
"github.com/gabriel-vasile/mimetype"
"github.com/spf13/cobra"
"io"
"os"
"path/filepath"
"strings"
)
var recursive, verbose, repair, appendOldName, onlyShowNotMatch, secondExt bool
var outputCsvPath string
var fromSize int
func init() {
Cmd.Flags().BoolVarP(&recursive, "recursive", "r", false, "递归检测文件夹中的所有文件")
Cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "详细模式,输出更多日志")
Cmd.Flags().BoolVarP(&repair, "repair", "R", false, "修复文件类型,尝试将文件类型修复为正确的类型")
Cmd.Flags().BoolVarP(&appendOldName, "append-mode", "a", false, "在修复文件名时,追加旧文件名后缀")
Cmd.Flags().StringVarP(&outputCsvPath, "output-csv", "o", "", "输出CSV文件路径若不指定则不输出CSV")
Cmd.Flags().IntVarP(&fromSize, "from-size", "s", 0, "需要检测的地址偏移量单位为字节默认从0开始检测负数表示从文件末尾开始计算偏移量")
Cmd.Flags().BoolVarP(&onlyShowNotMatch, "only-show-not-match", "m", false, "只显示文件类型不匹配的文件")
Cmd.Flags().BoolVarP(&secondExt, "second-ext", "S", false, "使用第二个扩展名进行匹配,适用于某些文件类型(如 .tar.gz .7z.001")
}
var Cmd = &cobra.Command{
Use: "mime",
Short: "文件类型检测",
Long: `mime - 文件类型检测`,
Run: func(cmd *cobra.Command, args []string) {
var c *csv.Writer
if len(args) == 0 {
starlog.Errorf("请指定文件路径\n")
os.Exit(1)
}
if outputCsvPath != "" {
file, err := os.Create(outputCsvPath)
if err != nil {
starlog.Errorf("创建CSV文件 %s 失败: %v\n", outputCsvPath, err)
os.Exit(1)
}
defer file.Close()
c = csv.NewWriter(file)
c.Write([]string{"File Path", "Extension", "Detect File Type", "Detect File Extension", "Match"})
defer c.Flush()
}
for _, path := range args {
if staros.IsFolder(path) {
for _, file := range getFiles(path, recursive) {
Detect(c, file, fromSize, onlyShowNotMatch)
}
} else {
Detect(c, path, fromSize, onlyShowNotMatch)
}
}
},
}
func getFiles(folder string, recurring bool) []string {
files := make([]string, 0)
err := filepath.Walk(folder, func(path string, info os.FileInfo, err error) error {
if err != nil {
starlog.Errorf("walk folder %s error: %v", folder, err)
return err
}
if info.IsDir() {
if recurring {
return nil // 继续递归
}
return filepath.SkipDir // 不递归子目录
}
files = append(files, path)
return nil
})
if err != nil {
starlog.Errorf("walk folder %s error: %v", folder, err)
}
return files
}
func Detect(c *csv.Writer, path string, fromSize int, onlyShowNotMatch bool) {
f, err := os.Open(path)
if err != nil {
starlog.Errorf("open file %s error: %v\n", path, err)
os.Exit(1)
}
if fromSize > 0 {
f.Seek(int64(fromSize), io.SeekStart)
} else if fromSize < 0 {
f.Seek(int64(fromSize), io.SeekEnd)
}
tp, err := mimetype.DetectReader(f)
f.Close()
if err != nil {
starlog.Errorf("detect file type error: %v\n", err)
os.Exit(1)
}
ext := strings.ToLower(filepath.Ext(path))
ext2 := strings.ToLower(filepath.Ext(strings.TrimRight(path, ext)))
if verbose {
starlog.Infof("file path: %s\n", path)
starlog.Infof("file type: %s\n", tp.String())
starlog.Infof("file ext: %s\n", tp.Extension())
if ext2 == tp.Extension() && secondExt {
if !onlyShowNotMatch {
starlog.Infof("file type %s match extension %s\n", tp.String(), ext2)
}
} else if ext != tp.Extension() && tp.Extension() != "" {
starlog.Warningf("file type %s not match extension %s\n", tp.String(), ext)
} else if !onlyShowNotMatch {
starlog.Infof("file type %s match extension %s\n", tp.String(), ext)
}
} else {
if ext2 == tp.Extension() && secondExt {
if !onlyShowNotMatch {
starlog.Infof("%s: %s (%s) matched %s\n", path, tp.String(), tp.Extension(), ext2)
}
} else if ext != tp.Extension() && tp.Extension() != "" {
starlog.Warningf("%s: %s (%s) not match %s\n", path, tp.String(), tp.Extension(), ext)
} else if !onlyShowNotMatch {
starlog.Infof("%s: %s (%s) matched %s\n", path, tp.String(), tp.Extension(), ext)
}
}
if c != nil {
match := "false"
if ext == tp.Extension() {
match = "true"
}
err = c.Write([]string{path, ext, tp.String(), tp.Extension(), match})
if err != nil {
starlog.Errorf("write csv file %s error: %v\n", outputCsvPath, err)
}
}
if repair && ext != tp.Extension() && tp.Extension() != "" {
newPath := path[:len(path)-len(ext)] + tp.Extension()
if appendOldName {
newPath = path + tp.Extension()
}
err = os.Rename(path, newPath)
if err != nil {
starlog.Errorf("rename file %s to %s error: %v", path, newPath, err)
os.Exit(1)
}
if verbose {
starlog.Infof("file %s renamed to %s\n", path, newPath)
} else {
starlog.Infof("renamed: %s -> %s\n", path, newPath)
}
}
}