ASP.NET 8 AOT 遍歷資料夾獲取檔名稱及時長

sun8134發表於2024-09-09

朋友下了N多影片

記不住資料夾下都有啥了…

問批處理怎麼匯出資料夾下所有檔名及影片時長…


批處理匯出檔名好弄,獲取影片時長真沒用過…

想到 .net 控制檯程式 AOT 釋出,不和批處理差不多效果…


新建個控制檯專案選下使用AOT

image



首先要獲取檔案的時長,我們需要用下 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)
		{
			// 最大遞迴深度設定為3
			const 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

image



最後就是AOT釋出了

目前vs還不支援直接AOT釋出(https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/aot/native-aot-tutorial?view=aspnetcore-8.0&tabs=visual-studio

需要自己手打下命令

image


到 \bin\Release\net8.0\win-x64\publish 下就能看到釋出的檔案了

執行下看看效果:

image


生成的csv檔案:

image

相關文章