Windows 10下如何快速批量修改视频描述类元数据?
批量清除视频描述类元数据(无重编码)
你需要的是模拟Windows资源管理器的元数据修改逻辑——直接修改文件属性而非重编码,以下是两种高效实现方案:
方案1:PowerShell 脚本(快速上手)
利用Windows Shell.Application COM对象直接操作文件属性,无需额外工具,速度和手动修改一致。
脚本代码
# 替换为你的目标视频文件夹路径 $targetFolder = "C:\Your\Video\Root\Folder" # 定义要清除的元数据字段(和资源管理器详情页显示的名称一致,中文系统用中文名称) $fieldsToClear = @( "Title", "Comments", "Subtitle", "Tags", "Keywords" ) $shell = New-Object -ComObject Shell.Application # 定义清除单个文件元数据的函数 function Clear-Metadata { param([string]$FilePath) $folder = $shell.Namespace((Split-Path $FilePath)) $fileItem = $folder.ParseName((Split-Path $FilePath -Leaf)) # 遍历找到每个字段对应的索引 foreach ($field in $fieldsToClear) { $fieldIndex = 0 for ($i = 0; $i -lt 200; $i++) { if ($folder.GetDetailsOf($folder.Items(), $i) -eq $field) { $fieldIndex = $i break } } # 清空字段值 if ($fieldIndex -ne 0) { $folder.GetDetailsOf($fileItem, $fieldIndex) = "" } } } # 递归遍历所有视频文件(可自行添加/移除格式后缀) Get-ChildItem -Path $targetFolder -Recurse -Include *.mp4,*.mkv,*.mov,*.avi,*.wmv | ForEach-Object { Write-Host "Processing: $($_.FullName)" Clear-Metadata -FilePath $_.FullName } # 释放COM对象,避免内存泄漏 [System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell) | Out-Null
使用说明
- 打开PowerShell,将上述代码粘贴进去(替换目标文件夹路径)。
- 若为中文系统,将
$fieldsToClear里的字段名改为中文(如"标题"、"评论")。 - 运行脚本即可批量清除指定字段的元数据。
方案2:C# 控制台程序(可复用工具)
直接调用Windows Property System API,稳定性更高,适合做成可执行文件重复使用,同样无重编码。
完整代码
using System; using System.IO; using System.Runtime.InteropServices; using System.Collections.Generic; namespace VideoMetadataCleaner { class Program { // Windows Property System API 导入 [DllImport("propsys.dll", CharSet = CharSet.Unicode)] private static extern int PSGetPropertyKeyFromName(string pszCanonicalName, out PROPERTYKEY pkey); [DllImport("propsys.dll", CharSet = CharSet.Unicode)] private static extern int PSGetPropertyStoreFromObject( [MarshalAs(UnmanagedType.IUnknown)] object punk, GETPROPERTYSTOREFLAGS flags, ref Guid riid, out IntPtr ppv); [DllImport("propsys.dll")] private static extern int IPropertyStore_SetValue(IntPtr pStore, ref PROPERTYKEY key, ref PROPVARIANT propvar); [DllImport("propsys.dll")] private static extern int IPropertyStore_Commit(IntPtr pStore); [StructLayout(LayoutKind.Sequential, Pack = 4)] private struct PROPERTYKEY { public Guid fmtid; public uint pid; } [StructLayout(LayoutKind.Explicit)] private struct PROPVARIANT { [FieldOffset(0)] public ushort vt; [FieldOffset(8)] public IntPtr pwszVal; } private const ushort VT_LPWSTR = 0x000B; private const int S_OK = 0; [Flags] private enum GETPROPERTYSTOREFLAGS { GPS_READWRITE = 0x00000002 } private static readonly Guid IID_IPropertyStore = new Guid("{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}"); private static readonly Guid IID_IShellItem = new Guid("{43826D1E-E718-42EE-BC55-A1E261C37BFE}"); // 标准属性键名称(不受系统语言影响) private static readonly List<string> TargetProperties = new List<string> { "System.Title", "System.Comment", "System.Subtitle", "System.Keywords", "System.Tags" }; static void Main(string[] args) { if (args.Length == 0) { Console.WriteLine("Usage: VideoMetadataCleaner.exe \"C:\\Your\\Video\\Folder\""); return; } string targetFolder = args[0]; if (!Directory.Exists(targetFolder)) { Console.WriteLine("Error: Target folder does not exist."); return; } // 遍历所有视频格式文件 string[] supportedExtensions = { ".mp4", ".mkv", ".mov", ".avi", ".wmv", ".flv" }; foreach (string file in Directory.EnumerateFiles(targetFolder, "*.*", SearchOption.AllDirectories)) { string ext = Path.GetExtension(file).ToLower(); if (supportedExtensions.Contains(ext)) { Console.WriteLine($"Processing: {file}"); CleanFileMetadata(file); } } Console.WriteLine("All files processed."); } private static void CleanFileMetadata(string filePath) { IntPtr shellItemPtr = IntPtr.Zero; IntPtr propertyStorePtr = IntPtr.Zero; try { // 创建ShellItem对象 int hr = SHCreateItemFromParsingName(filePath, IntPtr.Zero, ref IID_IShellItem, out shellItemPtr); if (hr != S_OK) throw new COMException("Failed to create ShellItem", hr); // 获取可写属性存储 hr = PSGetPropertyStoreFromObject( shellItemPtr, GETPROPERTYSTOREFLAGS.GPS_READWRITE, ref IID_IPropertyStore, out propertyStorePtr); if (hr != S_OK) throw new COMException("Failed to get property store", hr); // 逐个清空目标属性 foreach (string propName in TargetProperties) { if (PSGetPropertyKeyFromName(propName, out PROPERTYKEY propKey) != S_OK) continue; PROPVARIANT emptyValue = new PROPVARIANT(); emptyValue.vt = VT_LPWSTR; emptyValue.pwszVal = Marshal.StringToCoTaskMemUni(""); hr = IPropertyStore_SetValue(propertyStorePtr, ref propKey, ref emptyValue); if (hr != S_OK) Console.WriteLine($"Warning: Failed to clear {propName} for {filePath}"); Marshal.FreeCoTaskMem(emptyValue.pwszVal); } // 提交更改 hr = IPropertyStore_Commit(propertyStorePtr); if (hr != S_OK) throw new COMException("Failed to save changes", hr); } catch (Exception ex) { Console.WriteLine($"Error processing {filePath}: {ex.Message}"); } finally { // 释放资源 if (propertyStorePtr != IntPtr.Zero) Marshal.Release(propertyStorePtr); if (shellItemPtr != IntPtr.Zero) Marshal.Release(shellItemPtr); } } [DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern int SHCreateItemFromParsingName( string pszPath, IntPtr pbc, ref Guid riid, out IntPtr ppv); } }
使用说明
- 使用Visual Studio编译成控制台程序。
- 命令行运行:
VideoMetadataCleaner.exe "C:\Your\Video\Folder"。 - 此方案不受系统语言影响,属性键为Windows标准定义,兼容性更强。
核心注意事项
- 两种方案均无需重编码,处理速度仅取决于磁盘IO和文件数量,数百个视频可快速完成。
- 若遇到无法修改的文件,检查文件是否被进程占用(如正在播放),或当前用户是否有修改权限。
- PowerShell脚本需确保COM对象正常释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者JoeBobJr
相关产品推荐
相关产品推荐

