你刷到过那种“一年每天拍一秒钟”的视频吗?我特别佩服能做满三百六十五天的人,但说实话,等我真去试的时候,第一个月就乱套了——手机里存了一堆素材,文件名全是IMG_20250413_203114.mp4,根本不知道哪天拍的是哪天,我决定用Go语言写个小工具,把“第一天到第三十五天视频”这种整理工作变得不那么痛苦。
为什么偏偏是Go?
我承认,Python写脚本更快,但Go有它的倔脾气:编译出来就是个二进制文件,扔到哪儿都能跑,不用装环境,你要知道,我家的老笔记本连Python都懒得装,而且Go处理文件操作、并发重命名、时间计算这些事,写起来有种奇特的干脆感。
更重要的是,Go的标准库就把时间处理搞定了。time.Time直接带时区,不用像某些语言那样加载一吨依赖,这对我这种“能省一步是一步”的心态特别友好——毕竟365天视频整理这么琐碎的事,工具越轻越好。
我的需求其实很简单(但细节很烦)
动手之前,我给自己列了个需求清单,说白了就是:
- 输入:一个文件夹里乱糟糟的视频,文件名带日期(比如从GoPro、手机导出的)
- 输出:统一的命名格式,比如
day001.mp4、day002.mp4一直到day365.mp4 - 规则:按拍摄时间排序,而不是按文件名或者修改时间,不然你拷贝一次文件,顺序就全乱了
- 容错:有些视频可能没拍,名字要跳过(比如今天累了,没录),不能强制连续编号
后来我才发现,最麻烦的不是代码本身,而是“第一天”到底从哪天算起,是你开始拍的那天?还是元旦?还是听说这个挑战的那天?我最后决定用命令行参数让用户自己指定起始日期,默认用项目里最早那个视频的拍摄时间当第一天,这样最符合直觉。
核心代码长这样(带点我的碎碎念)
下面是我自己用的函数,逻辑不算复杂,但有几个坑我踩了很久,你可以直接拿去改。
package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"time"
)
type videoInfo struct {
path string
shotTime time.Time
dayIndex int
}
// 核心:从文件名里提取拍摄时间
// 不同设备命名不同,我把我遇到的情况写进来了
func extractShotTime(filename string) (time.Time, error) {
layouts := []string{
"20060102_150405", // 常见安卓格式: 20250414_183022
"2006-01-02 15.04.05", // 苹果有时候这样
"IMG_20060102_150405", // 苹果带IMG前缀
"20060102-150405", // GoPro风格
}
for _, layout := range layouts {
for _, sep := range []string{" ", "_", "-", "."} {
// 这里做了个笨办法:把文件名里的间隔统一替换,再匹配
tmp := strings.ReplaceAll(filename, sep, "_")
// 其实我省略了一些细节,但核心思路就是这样
}
t, err := time.Parse(layout, filename)
if err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("无法从 %s 中提取时间", filename)
}
然后主流程是这样的思路:
- 读目录,筛出所有
.mp4、.mov、.avi文件(我自己主要拍mp4) - 依次尝试提取拍摄时间,提取失败的扔到
error_log.txt里,不中断整个流程 - 排序(按时间从小到大),然后编号
- 关键一步:重命名为
dayXXX.mp4之前,先检查目标文件是否存在,比如你之前已经整理过一部分了,重新跑时不能把覆盖了,我加了个布尔参数--force,默认不覆盖。
对了,还有个特别容易忽视的细节:时区,如果你在手机上看拍摄时间是对的,但用Go解析时,默认用UTC,导致排序错乱,我一开始就栽在这上面,后来强制加了time.Local,才正常。
表格:365天视频整理的三阶段策略
我用这个工具整理的节奏大概分三阶段,给你做个参考,不用一次全整理完,我会骗自己“今天只搞一周的”。
| 阶段 | 时间范围 | 主要行动 | 工具重点 |
|---|---|---|---|
| 起步期 | 第1天 - 第30天 | 每天拍,但可能漏拍几天 | 工具要能跳过缺失的编号,不能中断 |
| 中期调整 | 第31天 - 第200天 | 开始有废片、重复片段 | 需要加一个--dedupe选项,按大小和hash去重 |
| 冲刺期 | 第201天 - 第365天 | 素材积累多,硬盘告急 | 批量压缩+重命名同时进行,用Go的os/exec调用ffmpeg |
这个表格的意思就是:别追求一步到位,你第一天写个简单版本,能跑就行;到了中期,你会发现缺漏;后期可能需要加压缩功能,Go的好处是编译快,改完立刻能跑。
并发重命名:多快好省但小心犯错
Go的goroutine太好用了,我忍不住就加了并行处理,但你要知道,文件重命名涉及到同一个目录的元数据操作,并发太高会有问题,我试过5个并发,结果有俩文件报错“文件名已存在”。
后来我改成这样:分两阶段,第一阶段并发读取所有文件信息(这个很快),第二阶段串行执行重命名,因为重命名本身只要毫秒级,串行根本感觉不到慢,但安全很多,代码长这样(简化版):
func renameSequentially(files []videoInfo) error {
for i := range files {
from := files[i].path
to := filepath.Join(filepath.Dir(from), fmt.Sprintf("day%03d.mp4", files[i].dayIndex))
if _, err := os.Stat(to); err == nil && !forceOverwrite {
continue // 目标已存在,跳过
}
if err := os.Rename(from, to); err != nil {
return fmt.Errorf("重命名失败: %s -> %s, 原因: %v", from, to, err)
}
// 小提示:打印进度,不然你以为卡死了
fmt.Printf("✓ %s -> %s\n", filepath.Base(from), filepath.Base(to))
}
return nil
}
这段代码看着简单,但那个fmt.Printf特别重要,整理365个文件的时候,下一秒没反应,你会怀疑程序挂了,有了这个输出,看着一行行跳过去,心里踏实。
整理一年视频,我悟到的三个道理
这工具写完之后,我真用了一年(坚持下来了,虽然中间断过十几天),回顾这段经历,有三个感受值得分享:
第一,缺失的日子不必硬补**,我中间感冒了差不多一周,没拍,原本想用旧素材凑数,后来想想没必要,工具帮我跳过那些天,让编号自动错位,但我自己心里清楚哪里断的,365天视频的意义不在连续性,而在你确实记录了某段时间。
第二,命名规则比你想的还重要**,当视频多到上千个,你按dayXXX排序,文件管理器里排列得整整齐齐,而且因为前面补了零,day2不会排在day10后面,这不算什么高深技巧,但用的时候会觉得“真是明智”。
第三,Go标准库的time包太够用了**,我一开始担心要引入什么复杂的时间库,其实没用上。time.Parse加上自定义格式,几行就搞定,标准库就是最可靠的,少折腾依赖,多留点时间给拍摄本身。
关于日志和错误处理(现实很骨感)
真实场景里,你的素材可能会出各种幺蛾子:某台相机的时间没设置对、有的视频是屏幕录制(时间戳异常)、还有从微信保存下来的视频(名字完全不规则),我的工具里加了个error_log.txt,所有解析不了的都写进去。

第一周跑完,日志里有二十多条,后来我耐心看,发现多数是微信保存的wx_camera_20250415_234213.mp4这种格式,于是我加了一行解析规则,专门对付它,看,工具就是这样“喂”出来的——不是一次写好的,是一边用一边补。
哦对,还有个大坑:文件名里可能有空格,Linux下没问题,但如果你在Windows上跑,重命名时带空格的文件名能烦死你,我统一在重命名前把空格替换成下划线,免得后续脚本出问题,这种事靠文档记录太麻烦,代码里顺手处理掉才省心。
最后分享下完整的命令行用法(我的日常操作)
我通常这样跑:
./videoday -input /home/me/videos/2025 -start "2025-01-01" -format mp4 -force=false
如果第一天不是1月1号,我会用-start指定,如果忘记指定,程序会自动找最早视频的拍摄时间。
还有一个-dry-run参数,很重要。先跑一遍,只打印不改文件名,看看会怎么命名,确认没问题了再真正执行,这习惯救了我好几次,有一次发现时区没设置对,差点把后半年视频全错位了。
这工具现在还在我的硬盘里,被我改得有点“四不像”了——因为中间加了好多功能(压缩、去重、甚至生成HTML索引页),但最核心的那个“从第一天到第三百六十五天视频”的rename功能,我一行没删,每次打开终端,跑一遍,看着那些day001.mp4、day002.mp4排得整整齐齐,就觉得这一年没白折腾。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://hljbesthome.com/keji/2515.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《从第一天到第三百六十五天,我用Go语言写了一个记录365天视频的傻瓜工具》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:你刷到过那种“一年每天拍一秒钟”的视频吗?我特别佩服能做满三百六十五天的人,但说实话,等我真去试的时候,第一个月就乱套了——手机里存了一...