You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

使用说明

  1. 打开PowerShell,将上述代码粘贴进去(替换目标文件夹路径)。
  2. 若为中文系统,将$fieldsToClear里的字段名改为中文(如"标题"、"评论")。
  3. 运行脚本即可批量清除指定字段的元数据。

方案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);
    }
}

使用说明

  1. 使用Visual Studio编译成控制台程序。
  2. 命令行运行:VideoMetadataCleaner.exe "C:\Your\Video\Folder"。
  3. 此方案不受系统语言影响,属性键为Windows标准定义,兼容性更强。

核心注意事项

  • 两种方案均无需重编码,处理速度仅取决于磁盘IO和文件数量,数百个视频可快速完成。
  • 若遇到无法修改的文件,检查文件是否被进程占用(如正在播放),或当前用户是否有修改权限。
  • PowerShell脚本需确保COM对象正常释放,避免内存泄漏。

内容的提问来源于stack exchange,提问作者JoeBobJr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 17:54:52