朋友下了N多视频
记不住文件夹下都有啥了…
问批处理怎么导出文件夹下所有文件名及视频时长…
批处理导出文件名好弄,获取视频时长真没用过…
想到 .net 控制台程序 AOT 发布,不和批处理差不多效果…
新建个控制台项目选下使用AOT
首先要获取文件的时长,我们需要用下 TagLibSharp
Install-Package TagLibSharp
然后是遍历文件夹,让万能的 chatgpt 写一个:
/// <summary>/// 列出指定目录及其子目录中的文件,限制递归深度。/// </summary>/// <param name="path">当前目录路径</param>/// <param name="writer">StreamWriter 对象,用于写入文件</param>/// <param name="currentDepth">当前递归深度</param>static void ListFilesAndDirectories(string path, StreamWriter writer, int currentDepth){// 最大递归深度设定为3const int maxDepth = 3;// 如果当前深度超过最大深度,则返回if (currentDepth > maxDepth){return;}try{// 获取当前目录下的所有文件string[] files = Directory.GetFiles(path);foreach (string file in files){if (file != outputFilePath && file != ownFilePath){FileInfo fileInfo = new FileInfo(file);string fileInfoText = $"{fileInfo.Name}, {fileInfo.DirectoryName}\\, {ConvertBytesToReadableSize(fileInfo.Length)} ";// 判断文件类型并获取时长(如果为音视频文件)if (IsMediaFile(fileInfo.Extension)){TimeSpan duration = GetMediaDuration(file);fileInfoText += $",{duration.ToString(@"hh\:mm\:ss")}";}else{fileInfoText += $",";}// 写入文件信息到文本文件Console.WriteLine($"文件名: {fileInfo.Name}, 大小: {ConvertBytesToReadableSize(fileInfo.Length)} 字节");writer.WriteLine(fileInfoText);}}// 获取当前目录下的所有子目录string[] directories = Directory.GetDirectories(path);foreach (string directory in directories){// 递归调用以列出子目录中的文件,并增加递归深度ListFilesAndDirectories(directory, writer, currentDepth + 1);}}catch (UnauthorizedAccessException ex){// 处理无权限访问的异常Console.WriteLine($"无法访问目录 {path}: {ex.Message}");writer.WriteLine($"无法访问目录 {path}: {ex.Message}");}catch (Exception ex){// 处理其他异常Console.WriteLine($"处理目录 {path} 时出错: {ex.Message}");writer.WriteLine($"处理目录 {path} 时出错: {ex.Message}");}}
我们根据后缀名来判断下是否为音视频文件:
/// <summary>/// 判断文件是否为音视频文件/// </summary>/// <param name="extension">文件扩展名</param>/// <returns>是否为音视频文件</returns>static bool IsMediaFile(string extension){string[] mediaExtensions = { ".mp3", ".wav", ".wma", ".m4a", ".mp4", ".avi", ".mkv", ".webm", ".mov" };return Array.Exists(mediaExtensions, e => e.Equals(extension, StringComparison.OrdinalIgnoreCase));}
如果是音视频文件,返回时长:
/// <summary>/// 获取音视频文件的时长/// </summary>/// <param name="filePath">音视频文件路径</param>/// <returns>时长</returns>static TimeSpan GetMediaDuration(string filePath){try{// 使用 TagLib 获取音视频文件时长var file = TagLib.File.Create(filePath);return file.Properties.Duration;}catch (Exception ex){Console.WriteLine($"无法获取文件 {filePath} 的时长: {ex.Message}");return TimeSpan.Zero;}}
最后格式化文件大小,好看一些:
/// <summary>/// 将字节转换为可读的文件大小格式(如 KB, MB, GB 等)。/// </summary>/// <param name="bytes">文件大小(以字节为单位)</param>/// <returns>可读的文件大小格式</returns>static string ConvertBytesToReadableSize(long bytes){if (bytes < 0){throw new ArgumentException("字节数不能为负数。", nameof(bytes));}// 定义文件大小单位及其缩写string[] sizeUnits = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };int unitIndex = 0;double size = bytes;// 不断除以 1024,直到找到合适的单位while (size >= 1024 && unitIndex < sizeUnits.Length - 1){size /= 1024;unitIndex++;}// 返回带有单位的文件大小,保留两位小数return $"{size:0.00} {sizeUnits[unitIndex]}";}
最后填充下main函数,我们创建一个csv用于写入数据
static void Main(string[] args){DateTime d1=DateTime.Now;// 获取当前目录string currentDirectory = Directory.GetCurrentDirectory();ownFilePath = Process.GetCurrentProcess().MainModule.FileName;string filrName = $"FileList{d1.ToString("yyyyMMddHHmmss")}.csv";// 定义输出文件路径outputFilePath = Path.Combine(currentDirectory, filrName);// 创建或覆盖输出文件using (StreamWriter writer = new StreamWriter(outputFilePath, false, System.Text.Encoding.UTF8)){writer.WriteLine("文件名,路径,大小,时长");Console.WriteLine("文件名,路径,大小,时长");// 递归列出当前目录及最多3层子目录的文件ListFilesAndDirectories(currentDirectory, writer, 0);}Console.WriteLine("遍历完毕,按回车退出!");Console.ReadLine();}
因为我们使用了第三方的包,在AOT发布前需要处理下,给项目添加个 rd.xml 文件,把我们的第三方包集成进去,文件内容如下:
<Directives><Application><Assembly Name="TagLibSharp" Dynamic="Required All"></Assembly></Application> </Directives>
然后修改项目文件,增加 rd.xml
最后就是AOT发布了
目前vs还不支持直接AOT发布(https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/aot/native-aot-tutorial?view=aspnetcore-8.0&tabs=visual-studio)
需要自己手打下命令
到 \bin\Release\net8.0\win-x64\publish 下就能看到发布的文件了
运行下看看效果:
生成的csv文件: