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

205 lines
7.5 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 filedate
import (
"b612.me/staros"
"fmt"
"github.com/spf13/cobra"
"os"
"path/filepath"
"regexp"
"strconv"
"time"
)
var aTime, mTime, cTime, allTime string // "2006-01-02 15:04:05" format
var fileRegexp string // 正则表达式匹配文件名
var recursive bool // 是否递归子目录
var dateFromName bool // 是否从文件名中提取日期
var dateFromNameReg string // 从文件名提取日期的正则表达式
var dateFromNameReplace string // 从文件名提取日期正则替代
var dateFromNameFormat string
var isTimestamp bool // 文件名是否是时间戳
var onlyModifyAccess bool // 只修改访问时间
var onlyModifyCreate bool // 只修改创建时间
var onlyModifyModify bool // 只修改修改时间
var excludeFolder bool // 是否排除目录本身
var Cmd = &cobra.Command{
Use: "filedate",
Short: "修改文件的创建/修改/访问时间",
Long: `修改文件的创建/修改/访问时间。
可以通过 --access, --modify, --create, --all 来设置不同的时间。
例如:
b612 filedate file.txt --access "2023-10-01 12:00:00" --modify "2023-10-01 12:00:00"
b612 filedate dir/ --all "2023-10-01 12:00:00" -r
也可以通过 --regexp 来匹配文件名,或者通过 --date-from-name 来从文件名中提取日期。
比如文件名为IMG_20160711_161625.jpg,,可以通过如下命令来设置时间:
b612 filedate -D -y '$1$2' -x 20060102150405 -z '.*?(\d+)_(\d+).+' .\IMG_20160711_161625.jpg
`,
Run: run,
}
func init() {
Cmd.Flags().StringVarP(&aTime, "access", "a", "", "设置访问时间,格式: 2006-01-02 15:04:05")
Cmd.Flags().StringVarP(&mTime, "modify", "m", "", "设置修改时间,格式: 2006-01-02 15:04:05")
Cmd.Flags().StringVarP(&cTime, "create", "c", "", "设置创建时间,格式: 2006-01-02 15:04:05")
Cmd.Flags().StringVarP(&allTime, "all", "l", "", "设置所有时间,格式: 2006-01-02 15:04:05")
Cmd.Flags().StringVarP(&fileRegexp, "regexp", "R", "", "正则表达式匹配文件名")
Cmd.Flags().BoolVarP(&recursive, "recursive", "r", false, "递归子目录")
Cmd.Flags().BoolVarP(&dateFromName, "date-from-name", "D", false, "从文件名中提取日期")
Cmd.Flags().StringVarP(&dateFromNameReg, "date-from-name-regex", "z", "", "从文件名提取日期的正则表达式")
Cmd.Flags().StringVarP(&dateFromNameReplace, "date-from-name-replace", "y", "", "从文件名提取日期的替换表达式")
Cmd.Flags().StringVarP(&dateFromNameFormat, "date-from-name-format", "x", "2006-01-02 15:04:05", "从文件名提取日期的格式")
Cmd.Flags().BoolVarP(&isTimestamp, "timestamp", "t", false, "文件名是否是时间戳")
Cmd.Flags().BoolVarP(&onlyModifyAccess, "only-modify-access", "A", false, "只修改访问时间")
Cmd.Flags().BoolVarP(&onlyModifyCreate, "only-modify-create", "C", false, "只修改创建时间")
Cmd.Flags().BoolVarP(&onlyModifyModify, "only-modify-modify", "M", false, "只修改修改时间")
Cmd.Flags().BoolVarP(&excludeFolder, "exclude-folder", "e", false, "排除目录本身,不修改目录的时间")
}
func run(cmd *cobra.Command, args []string) {
var aDate, mDate, cDate, allDate time.Time
var err error
if aTime != "" && (onlyModifyAccess || !(onlyModifyCreate || onlyModifyModify)) {
aDate, err = time.ParseInLocation("2006-01-02 15:04:05", aTime, time.Local)
if err != nil {
cmd.PrintErrf("解析访问时间失败: %v\n", err)
return
}
}
if mTime != "" && (onlyModifyCreate || !(onlyModifyAccess || onlyModifyModify)) {
mDate, err = time.ParseInLocation("2006-01-02 15:04:05", mTime, time.Local)
if err != nil {
cmd.PrintErrf("解析修改时间失败: %v\n", err)
return
}
}
if cTime != "" && (onlyModifyCreate || !(onlyModifyAccess || onlyModifyModify)) {
cDate, err = time.ParseInLocation("2006-01-02 15:04:05", cTime, time.Local)
if err != nil {
cmd.PrintErrf("解析创建时间失败: %v\n", err)
return
}
}
if allTime != "" {
allDate, err = time.ParseInLocation("2006-01-02 15:04:05", allTime, time.Local)
if err != nil {
cmd.PrintErrf("解析所有时间失败: %v\n", err)
return
}
if mDate.IsZero() && (onlyModifyCreate || !(onlyModifyAccess || onlyModifyModify)) {
mDate = allDate
}
if cDate.IsZero() && (onlyModifyCreate || !(onlyModifyAccess || onlyModifyModify)) {
cDate = allDate
}
if aDate.IsZero() && (onlyModifyAccess || !(onlyModifyCreate || onlyModifyModify)) {
aDate = allDate
}
}
var reg, namereg *regexp.Regexp
if dateFromName {
if dateFromNameReg == "" {
cmd.PrintErrf("未指定从文件名提取日期的正则表达式\n")
return
}
if dateFromNameReplace == "" {
cmd.PrintErrf("未指定从文件名提取日期的替换表达式\n")
return
}
if dateFromNameFormat == "" {
cmd.PrintErrf("未指定从文件名提取日期的格式\n")
return
}
namereg, err = regexp.Compile(dateFromNameReg)
if err != nil {
cmd.PrintErrf("解析正则表达式失败: %v\n", err)
return
}
}
if fileRegexp != "" {
reg, err = regexp.Compile(fileRegexp)
if err != nil {
cmd.PrintErrf("解析正则表达式失败: %v\n", err)
return
}
}
for _, path := range args {
SetFileTimes(path, reg, namereg, cDate, aDate, mDate)
}
}
func SetFileTimes(path string, reg, namereg *regexp.Regexp, ctime, atime, mtime time.Time) error {
setFile := func(path string, info os.FileInfo) error {
var err error
if reg != nil && !reg.MatchString(info.Name()) {
return nil // 跳过不匹配的文件
}
if dateFromName && namereg != nil {
date := namereg.ReplaceAllString(filepath.Base(path), dateFromNameReplace)
if date == "" {
fmt.Printf("从文件名提取日期失败: %s\n", path)
return nil // 跳过无法提取日期的文件
}
var realDate time.Time
if !isTimestamp {
realDate, err = time.ParseInLocation(dateFromNameFormat, date, time.Local)
if err != nil {
fmt.Printf("解析文件名日期失败: %s, 错误: %v\n", path, err)
return nil // 跳过无法解析日期的文件
}
} else {
tmp, err := strconv.ParseInt(date, 10, 64)
if err != nil {
fmt.Printf("解析时间戳失败: %s, 错误: %v\n", path, err)
return nil // 跳过无法解析时间戳的文件
}
realDate = time.Unix(tmp, 0)
}
if onlyModifyCreate || !(onlyModifyAccess || onlyModifyModify) {
mtime = realDate
}
if onlyModifyCreate || !(onlyModifyAccess || onlyModifyModify) {
ctime = realDate
}
if onlyModifyAccess || !(onlyModifyCreate || onlyModifyModify) {
atime = realDate
}
}
if err := SetFileTime(path, ctime, atime, mtime); err != nil {
return fmt.Errorf("设置文件时间失败: %s, 错误: %v", path, err)
}
fmt.Printf("已设置文件时间: %s\n", path)
return nil
}
if !staros.Exists(path) {
return fmt.Errorf("文件不存在: %s", path)
}
if staros.IsFile(path) {
info, err := os.Stat(path)
if err != nil {
return fmt.Errorf("获取文件信息失败: %s, 错误: %v", path, err)
}
return setFile(path, info)
}
return filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if staros.IsFile(path) {
return setFile(path, info)
}
if staros.IsFolder(path) {
if recursive {
err = SetFileTimes(path, reg, namereg, ctime, atime, mtime)
if err != nil {
return fmt.Errorf("递归设置文件时间失败: %s, 错误: %v", path, err)
}
}
if excludeFolder {
return nil // 如果排除目录本身,则不处理目录的时间
}
return setFile(path, info) // 处理目录本身
}
return nil
})
}