结合录音元数据与固定时长递推批量重命名WAV音频的方案
批量重命名WAV音频的实现方案
核心逻辑说明
不需要逐个调用stat、ffmpeg、soxi读取单文件元数据,直接依托现有已知信息计算每个文件的起始时间,处理速度可达到毫秒级:
- 基准时间来源:当前所在文件夹名记录了录音的完整日期、整体起始时间,第一个文件的创建时间(stat输出中的Birth time)和文件夹记录的起始时间完全匹配
- 时间顺延规则:每段音频固定时长为11分38.26秒,按照文件名中的数字序号,相对第一个文件做等长时间偏移即可算出每段的精确起始时间
- 输出格式完全匹配要求:
提取的原文件序号_计算得到的YYYYMMDD-HHMMSS.wav
方案1:zsh + Unix原生工具实现(零额外依赖)
适配macOS原生zsh环境,无需安装第三方工具,步骤如下:
- 先从当前文件夹名拆分提取基础时间参数
- 动态识别所有音频文件的数字序号基准,避免硬编码序号值
- 先执行dry-run打印所有重命名映射,核对无误后再实际执行改名操作
可直接复用的代码:
# 获取当前目录名 current_dir_name=${PWD:t} # 按下划线拆分文件夹字段,格式为 Audios_YYMMDD_起始时分秒_结束时分秒 dir_fields=(${(s:_:)current_dir_name}) yyMMDD_tag=${dir_fields[2]} # 转换为20xx年的完整日期格式 full_date_str="20${yyMMDD_tag}" # 解析首个文件的起始时间为Unix时间戳(适配macOS的date命令) base_start_ts=$(date -j -f "%y%m%d %H%M%S" "${yyMMDD_tag} ${dir_fields[3]}" "+%s") # 单段固定时长(秒,来自ffmpeg读取的精确值) seg_length=698.26 # 动态提取所有文件的最小序号作为基准,自动适配任意起始序号 min_seq=$(ls -1 ${yyMMDD_tag}_*.wav | awk -F'[_.]' '{print $2}' | sort -n | head -1) # 遍历所有匹配命名规则的wav文件,按数字序号升序处理 for wav_path in $(ls -1 ${yyMMDD_tag}_*.wav | sort -t_ -k2 -n); do # 拆分当前文件的序号部分,去掉.wav后缀 cur_seq=${${wav_path:t}:r} cur_seq=${cur_seq#${yyMMDD_tag}_} # 计算相对基准序号的偏移量,10#前缀避免zsh把带前导零的字符串识别为八进制 seq_offset=$(( 10#$cur_seq - 10#$min_seq )) # 计算当前文件的起始时间戳 cur_ts=$(echo "$base_start_ts + $seq_offset * $seg_length" | bc) # 转换为要求的YYYYMMDD-HHMMSS格式 cur_time_str=$(date -j -f "%s" "$cur_ts" "+%Y%m%d-%H%M%S") # 生成新文件名 new_filename="${cur_seq}_${cur_time_str}.wav" # 先打印重命名映射,核对完成后再取消最后一行的注释执行实际操作 echo "待重命名: ${wav_path} -> ${new_filename}" # mv "${wav_path}" "${new_filename}" done
注意事项:
- 首次执行一定要先保留打印逻辑,把计算出来的时间和单文件的stat输出对比,确认没有偏移后再执行实际的
mv操作 - zsh中处理带前导零的数字时一定要加
10#前缀,否则会触发八进制解析错误,导致序号偏移计算完全出错
方案2:Python实现(跨平台,容错性更强)
不依赖macOS特有的date命令,处理浮点时间、异常文件名的容错能力更好,代码可读性更高:
import os from datetime import datetime, timedelta from pathlib import Path # 读取当前目录的基础信息 current_dir = Path.cwd() dir_name = current_dir.name dir_segments = dir_name.split("_") yyMMDD_tag = dir_segments[1] full_date = f"20{yyMMDD_tag}" base_start_hms = dir_segments[2] # 初始化基准时间、单段时长 base_start_time = datetime.strptime(f"{full_date} {base_start_hms}", "%Y%m%d %H%M%S") seg_duration = timedelta(seconds=698.26) # 收集所有匹配原命名规则的wav文件,提取序号后排序 file_list = [] for wav_file in current_dir.glob(f"{yyMMDD_tag}_*.wav"): # 从文件名拆分序号部分 file_seq_str = wav_file.stem.split("_")[1] file_seq_num = int(file_seq_str) file_list.append( (file_seq_num, file_seq_str, wav_file) ) file_list.sort(key=lambda x: x[0]) # 以最小序号为基准计算偏移 base_seq = file_list[0][0] for seq_num, seq_str, file_path in file_list: offset = seq_num - base_seq cur_start_time = base_start_time + seg_duration * offset # 生成新文件名 new_name = f"{seq_str}_{cur_start_time.strftime('%Y%m%d-%H%M%S')}.wav" new_path = file_path.parent / new_name # 打印映射关系,核对后取消重命名逻辑的注释 print(f"待重命名: {file_path.name} -> {new_name}") # file_path.rename(new_path)
效率对比
传统逐个调用soxi/ffmpeg/stat读取60个文件元数据的方案,单文件平均耗时0.2秒,整体需要12秒以上;上述两个方案依托现有已知信息计算时间,60个文件的处理耗时不到0.1秒,完全不需要逐个读取文件内容。
内容的提问来源于stack exchange,提问作者Mario Rollo
相关产品推荐
相关产品推荐

