读/写“扩展”文件属性 (C#)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/220097/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:39:44  来源:igfitidea点击:

Read/Write 'Extended' file properties (C#)

c#extended-properties

提问by David Hayes

I'm trying to find out how to read/write to the extended file properties in C# e.g. Comment, Bit Rate, Date Accessed, Category etc that you can see in Windows explorer. Any ideas how to do this? EDIT: I'll mainly be reading/writing to video files (AVI/DIVX/...)

我试图找出如何读/写 C# 中的扩展文件属性,例如注释、比特率、访问日期、类别等,您可以在 Windows 资源管理器中看到这些属性。任何想法如何做到这一点?编辑:我主要是读/写视频文件(AVI/DIVX/...)

采纳答案by csharptest.net

For those of not crazy about VB, here it is in c#:

对于那些不喜欢 VB 的人,这里是 C#:

Note, you have to add a reference to Microsoft Shell Controls and Automationfrom the COM tab of the References dialog.

请注意,您必须从“引用”对话框的“COM”选项卡中添加对Microsoft Shell 控件和自动化的引用。

public static void Main(string[] args)
{
    List<string> arrHeaders = new List<string>();

    Shell32.Shell shell = new Shell32.Shell();
    Shell32.Folder objFolder;

    objFolder = shell.NameSpace(@"C:\temp\testprop");

    for( int i = 0; i < short.MaxValue; i++ )
    {
        string header = objFolder.GetDetailsOf(null, i);
        if (String.IsNullOrEmpty(header))
            break;
        arrHeaders.Add(header);
    }

    foreach(Shell32.FolderItem2 item in objFolder.Items())
    {
        for (int i = 0; i < arrHeaders.Count; i++)
        {
            Console.WriteLine(
              $"{i}\t{arrHeaders[i]}: {objFolder.GetDetailsOf(item, i)}");
        }
    }
}

回答by Mark Cidade

There's a CodeProject articlefor an ID3 reader. And a thread at kixtart.orgthat has more information for other properties. Basically, you need to call the GetDetailsOf()methodon the foldershell object for shell32.dll.

一篇针对 ID3 阅读器的 CodeProject 文章。以及kixtart.org上的一个线程,其中包含有关其他属性的更多信息。基本上,你需要调用GetDetailsOf()方法上的文件夹壳对象shell32.dll

回答by mockobject

I'm not sure what types of files you are trying to write the properties for but taglib-sharpis an excellent open source tagging library that wraps up all this functionality nicely. It has a lot of built in support for most of the popular media file types but also allows you to do more advanced tagging with pretty much any file.

我不确定您要为哪些类型的文件编写属性,但taglib-sharp是一个出色的开源标记库,它很好地包含了所有这些功能。它对大多数流行的媒体文件类型有很多内置支持,但也允许您对几乎任何文件进行更高级的标记。

EDIT:I've updated the link to taglib sharp. The old link no longer worked.

编辑:我已经更新了 taglib 锐利的链接。旧链接不再有效。

EDIT:Updated the link once again per kzu's comment.

编辑:根据 kzu 的评论再次更新链接。

回答by Dirk Vollmar

This sample in VB.NET reads all extended properties:

VB.NET 中的此示例读取所有扩展属性:

Sub Main()
        Dim arrHeaders(35)

        Dim shell As New Shell32.Shell
        Dim objFolder As Shell32.Folder

        objFolder = shell.NameSpace("C:\tmp")

        For i = 0 To 34
            arrHeaders(i) = objFolder.GetDetailsOf(objFolder.Items, i)
        Next
        For Each strFileName In objfolder.Items
            For i = 0 To 34
                Console.WriteLine(i & vbTab & arrHeaders(i) & ": " & objfolder.GetDetailsOf(strFileName, i))
            Next
        Next

    End Sub

You have to add a reference to Microsoft Shell Controls and Automationfrom the COMtab of the Referencesdialog.

您必须从“引用”对话框的“ COM”选项卡中添加对Microsoft Shell 控件和自动化引用

回答by JERKER

Thank you guys for this thread! It helped me when I wanted to figure out an exe's file version. However, I needed to figure out the last bit myself of what is called Extended Properties.

谢谢你们这个话题!当我想找出 exe 的文件版本时,它对我有所帮助。但是,我需要自己弄清楚所谓的扩展属性的最后一点。

If you open properties of an exe (or dll) file in Windows Explorer, you get a Version tab, and a view of Extended Properties of that file. I wanted to access one of those values.

如果您在 Windows 资源管理器中打开 exe(或 dll)文件的属性,您会看到一个版本选项卡,以及该文件的扩展属性视图。我想访问这些值之一。

The solution to this is the property indexer FolderItem.ExtendedProperty and if you drop all spaces in the property's name, you'll get the value. E.g. File Version goes FileVersion, and there you have it.

对此的解决方案是属性索引器 FolderItem.ExtendedProperty,如果您删除属性名称中的所有空格,您将获得该值。例如,文件版本变为文件版本,您就拥有它了。

Hope this helps anyone else, just thought I'd add this info to this thread. Cheers!

希望这对其他人有帮助,只是想我会将此信息添加到此线程。干杯!

回答by RajeshKdev

GetDetailsOf()Method - Retrieves details about an item in a folder. For example, its size, type, or the time of its last modification. File Properties may vary based on the Windows-OSversion.

GetDetailsOf()方法 - 检索有关文件夹中项目的详细信息。例如,它的大小、类型或上次修改的时间。文件属性可能因Windows-OS版本而异。

List<string> arrHeaders = new List<string>();

 Shell shell = new ShellClass();
 Folder rFolder = shell.NameSpace(_rootPath);
 FolderItem rFiles = rFolder.ParseName(filename);

 for (int i = 0; i < short.MaxValue; i++)
 {
      string value = rFolder.GetDetailsOf(rFiles, i).Trim();
      arrHeaders.Add(value);
 }

回答by Martin Schneider

Solution 2016

解决方案 2016

Add following NuGet packages to your project:

将以下 NuGet 包添加到您的项目中:

  • Microsoft.WindowsAPICodePack-Shellby Microsoft
  • Microsoft.WindowsAPICodePack-Coreby Microsoft
  • Microsoft.WindowsAPICodePack-Shell微软
  • Microsoft.WindowsAPICodePack-Core微软

Read and Write Properties

读写属性

using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

string filePath = @"C:\temp\example.docx";
var file = ShellFile.FromFilePath(filePath);

// Read and Write:

string[] oldAuthors = file.Properties.System.Author.Value;
string oldTitle = file.Properties.System.Title.Value;

file.Properties.System.Author.Value = new string[] { "Author #1", "Author #2" };
file.Properties.System.Title.Value = "Example Title";

// Alternate way to Write:

ShellPropertyWriter propertyWriter =  file.Properties.GetPropertyWriter();
propertyWriter.WriteProperty(SystemProperties.System.Author, new string[] { "Author" });
propertyWriter.Close();

Important:

重要的:

The file must be a valid one, created by the specific assigned software. Every file type has specific extended file properties and not all of them are writable.

该文件必须是由指定的特定软件创建的有效文件。每种文件类型都有特定的扩展文件属性,并非所有文件都是可写的。

If you right-click a file on desktop and cannot edit a property, you wont be able to edit it in code too.

如果您右键单击桌面上的文件并且无法编辑属性,您也将无法在代码中编辑它。

Example:

例子:

  • Create txt file on desktop, rename its extension to docx. You can't edit its Authoror Titleproperty.
  • Open it with Word, edit and save it. Now you can.
  • 在桌面上创建txt文件,将其扩展名重命名为docx。您不能编辑它的AuthorTitle属性。
  • 用 Word 打开它,编辑并保存它。现在你可以。

So just make sure to use some trycatch

所以只要确保使用一些 trycatch

Further Topic: MSDN: Implementing Property Handlers

更多主题: MSDN:实现属性处理程序

回答by nawfal

Jerker's answer is little simpler. Here's sample code which works from MS:

Jerker 的回答要简单一些。这是适用于 MS的示例代码:

var folder = new Shell().NameSpace(folderPath);
foreach (FolderItem2 item in folder.Items())
{
    var company = item.ExtendedProperty("Company");
    var author = item.ExtendedProperty("Author");
    // Etc.
}

For those who can't reference shell32 statically, you can invoke it dynamically like this:

对于那些不能静态引用 shell32 的人,你可以像这样动态调用它:

var shellAppType = Type.GetTypeFromProgID("Shell.Application");
dynamic shellApp = Activator.CreateInstance(shellAppType);
var folder = shellApp.NameSpace(folderPath);
foreach (var item in folder.Items())
{
    var company = item.ExtendedProperty("Company");
    var author = item.ExtendedProperty("Author");
    // Etc.
}

回答by Rohan

  • After looking at a number of solutions on this thread and elsewhere the following code was put together. This is only to read a property.
  • I could not get the Shell32.FolderItem2.ExtendedProperty function to work, it is supposed to take a string value and return the correct value and type for that property... this was always null for me and developer reference resources were very thin.
  • The WindowsApiCodePackseems to have been abandoned by Microsoft which brings us the code below.
  • 在查看此线程和其他地方的许多解决方案后,将以下代码放在一起。这只是为了读取一个属性。
  • 我无法让 Shell32.FolderItem2.ExtendedProperty 函数工作,它应该采用一个字符串值并返回该属性的正确值和类型......这对我来说始终为空,开发人员参考资源非常少。
  • WindowsApiCodePack似乎已经被微软放弃这给我们带来了下面的代码。

Use:

用:

string propertyValue = GetExtendedFileProperty("c:\temp\FileNameYouWant.ext","PropertyYouWant");
  1. Will return you the value of the extended property you want as a string for the given file and property name.
  2. Only loops until it found the specified property - not until all properties are discovered like some sample code
  3. Will work on Windows versions like Windows server 2008 where you will get the error "Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'"if just trying to create the Shell32 Object normally.

    public static string GetExtendedFileProperty(string filePath, string propertyName)
    {
        string value = string.Empty;
        string baseFolder = Path.GetDirectoryName(filePath);
        string fileName = Path.GetFileName(filePath);
    
        //Method to load and execute the Shell object for Windows server 8 environment otherwise you get "Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'"
        Type shellAppType = Type.GetTypeFromProgID("Shell.Application");
        Object shell = Activator.CreateInstance(shellAppType);
        Shell32.Folder shellFolder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { baseFolder });
    
        //Parsename will find the specific file I'm looking for in the Shell32.Folder object
        Shell32.FolderItem folderitem = shellFolder.ParseName(fileName);
        if (folderitem != null)
        {
            for (int i = 0; i < short.MaxValue; i++)
            {
                //Get the property name for property index i
                string property = shellFolder.GetDetailsOf(null, i);
    
                //Will be empty when all possible properties has been looped through, break out of loop
                if (String.IsNullOrEmpty(property)) break;
    
                //Skip to next property if this is not the specified property
                if (property != propertyName) continue;    
    
                //Read value of property
                value = shellFolder.GetDetailsOf(folderitem, i);
            }
        }
        //returns string.Empty if no value was found for the specified property
        return value;
    }
    
  1. 将返回您想要的扩展属性的值作为给定文件和属性名称的字符串。
  2. 只循环直到找到指定的属性 - 直到所有属性都像一些示例代码一样被发现
  3. 将在 Windows Server 2008 等 Windows 版本上工作,如果只是尝试正常创建 Shell32 对象,您将收到错误“无法将类型为 'System.__ComObject' 的 COM 对象转换为接口类型'Shell32.Shell'”

    public static string GetExtendedFileProperty(string filePath, string propertyName)
    {
        string value = string.Empty;
        string baseFolder = Path.GetDirectoryName(filePath);
        string fileName = Path.GetFileName(filePath);
    
        //Method to load and execute the Shell object for Windows server 8 environment otherwise you get "Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'"
        Type shellAppType = Type.GetTypeFromProgID("Shell.Application");
        Object shell = Activator.CreateInstance(shellAppType);
        Shell32.Folder shellFolder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { baseFolder });
    
        //Parsename will find the specific file I'm looking for in the Shell32.Folder object
        Shell32.FolderItem folderitem = shellFolder.ParseName(fileName);
        if (folderitem != null)
        {
            for (int i = 0; i < short.MaxValue; i++)
            {
                //Get the property name for property index i
                string property = shellFolder.GetDetailsOf(null, i);
    
                //Will be empty when all possible properties has been looped through, break out of loop
                if (String.IsNullOrEmpty(property)) break;
    
                //Skip to next property if this is not the specified property
                if (property != propertyName) continue;    
    
                //Read value of property
                value = shellFolder.GetDetailsOf(folderitem, i);
            }
        }
        //returns string.Empty if no value was found for the specified property
        return value;
    }
    

回答by pasx

Here is a solution for reading - not writing - the extended properties based on what I found on this page and at help with shell32 objects.

这是基于我在本页和shell32 对象帮助中找到的内容的读取而不是写入扩展属性的解决方案。

To be clear this is a hack. It looks like this code will still run on Windows 10 but will hit on some empty properties. Previous version of Windows should use:

需要明确的是,这是一个黑客攻击。看起来此代码仍将在 Windows 10 上运行,但会遇到一些空属性。以前版本的 Windows 应该使用:

        var i = 0;
        while (true)
        {
            ...
            if (String.IsNullOrEmpty(header)) break;
            ...
            i++;

On Windows 10 we assume that there are about 320 properties to read and simply skip the empty entries:

在 Windows 10 上,我们假设有大约 320 个属性可供读取,只需跳过空条目:

    private Dictionary<string, string> GetExtendedProperties(string filePath)
    {
        var directory = Path.GetDirectoryName(filePath);
        var shell = new Shell32.Shell();
        var shellFolder = shell.NameSpace(directory);
        var fileName = Path.GetFileName(filePath);
        var folderitem = shellFolder.ParseName(fileName);
        var dictionary = new Dictionary<string, string>();
        var i = -1;
        while (++i < 320)
        {
            var header = shellFolder.GetDetailsOf(null, i);
            if (String.IsNullOrEmpty(header)) continue;
            var value = shellFolder.GetDetailsOf(folderitem, i);
            if (!dictionary.ContainsKey(header)) dictionary.Add(header, value);
            Console.WriteLine(header +": " + value);
        }
        Marshal.ReleaseComObject(shell);
        Marshal.ReleaseComObject(shellFolder);
        return dictionary;
    }

As mentioned you need to reference the Com assembly Interop.Shell32.

如前所述,您需要引用 Com 程序集 Interop.Shell32。

If you get an STA related exception, you will find the solution here:

如果您收到 STA 相关异常,您将在此处找到解决方案:

Exception when using Shell32 to get File extended properties

使用 Shell32 获取文件扩展属性时的异常

I have no idea what those properties names would be like on a foreign system and couldn't find information about which localizable constants to use in order to access the dictionary. I also found that not all the properties from the Properties dialog were present in the dictionary returned.

我不知道这些属性名称在外部系统上会是什么样子,并且找不到有关使用哪些可本地化常量来访问字典的信息。我还发现,并非“属性”对话框中的所有属性都出现在返回的字典中。

BTW this is terribly slow and - at least on Windows 10 - parsing dates in the string retrieved would be a challenge so using this seems to be a bad idea to start with.

顺便说一句,这非常慢,并且 - 至少在 Windows 10 上 - 解析检索到的字符串中的日期将是一个挑战,因此使用它似乎是一个坏主意。

On Windows 10 you should definitely use the Windows.Storage library which contains the SystemPhotoProperties, SystemMusicProperties etc. https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

在 Windows 10 上,您绝对应该使用包含 SystemPhotoProperties、SystemMusicProperties 等的 Windows.Storage 库。 https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

And finally, I posted a much better solution that uses WindowsAPICodePack there

最后,我发布一个更好的解决方案,它使用WindowsAPICodePack