Чтение / запись расширенных свойств файла (C #)

104

Я пытаюсь узнать, как читать / писать в расширенные свойства файла в C #, например, комментарий, битрейт, дату доступа, категорию и т. Д., Которые вы можете увидеть в проводнике Windows. Есть идеи, как это сделать? РЕДАКТИРОВАТЬ: в основном я буду читать / писать в видео файлы (AVI / DIVX / ...)

Дэвид Хейс
источник
3
На этот вопрос явно нет ответа, поскольку принятый ответ показывает только, как получить расширенные свойства, а не как их установить .
Дмитрий Нестерук
1
Для установки расширенных свойств см stackoverflow.com/questions/5337683/...
VoteCoffee

Ответы:

83

Для тех, кто не без ума от VB, вот он на C #:

Обратите внимание, что вам необходимо добавить ссылку на Microsoft Shell Controls and Automation на вкладке COM диалогового окна References.

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)}");
        }
    }
}
csharptest.net
источник
3
как установить одно из этих значений? например, для автора или издателя файла .txt. Я выиграл 7 и использовал это, и он показывает пустых автора и издателя и 282 других свойства
Вайбхав Гарг,
1
@Vainbhav - Вы не можете их установить.
csharptest.net
26
Вы должны добавить ссылку на Microsoft Shell Controls and Automation на вкладке COM диалогового окна Refences.
csharptest.net
2
Как их УСТАНОВИТЬ, лучше расскажем в этом вопросе: stackoverflow.com/questions/5337683/…
Николас Рауль,
1
В Windows 10 он возвращает только 52 поля, не включая частоту кадров, высоту кадра, ширину и т. Д.?
Мин Нгуен
27

Есть статья CodeProject для читателей ID3. И ветка на kixtart.org, в которой есть дополнительная информация о других свойствах. В принципе, вы должны вызвать GetDetailsOf()метод на папке объекта оболочки для shell32.dll.

Марк Сидаде
источник
Спасибо, я смогу извлечь из этого то, что мне нужно,
Дэвид Хейс
26

Решение 2016

Добавьте в проект следующие пакеты NuGet:

  • Microsoft.WindowsAPICodePack-Shell от Microsoft
  • Microsoft.WindowsAPICodePack-Core от Microsoft

Читать и писать свойства

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();

Важный:

Файл должен быть действительным, созданным с помощью определенного назначенного программного обеспечения. Каждый тип файла имеет определенные расширенные свойства файла, и не все из них доступны для записи.

Если вы щелкните правой кнопкой мыши файл на рабочем столе и не можете изменить свойство, вы также не сможете редактировать его в коде.

Пример:

  • Создайте txt файл на рабочем столе, переименуйте его расширение в docx. Вы не можете редактировать его Authorили Titleсвойство.
  • Откройте его в Word, отредактируйте и сохраните. Теперь вы можете.

Так что не забудьте использовать try catch

Дополнительная тема: MSDN: реализация обработчиков свойств

Мартин Шнайдер
источник
Я не вижу пакетов с такими именами от Microsoft
Джейкоб Брюэр
1
@JacobBrewer На самом деле это тот, который был загружен "acdvorak": nuget.org/packages/Microsoft.WindowsAPICodePack-Shell . В Visual Studio NuGet-Package-Manager он отображается как «от Microsoft». Другие пакеты с похожими именами являются его ветвями и также могут работать правильно или даже лучше. Я не знаю ...
Мартин Шнайдер
25

Этот пример в 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

Вы должны добавить ссылку на Microsoft Shell Controls and Automation на вкладке COM диалогового окна References .

Дирк Фольмар
источник
2
Стоит отметить, что в Windows 7 (по крайней мере) вы можете увеличить размер arrHeaders до чуть более 280 и получить обратно много дополнительных метаданных. Я обнаружил это, когда искал способ получить метаданные из файла WTV (телешоу, записанное в Windows 7 Media Center).
Ричард
1
Первый цикл для i = от 0 до 34 должен быть от i = 0 до Integer.MaxValue. Затем проверьте возвращаемое значение objFolder.GetDetailsOf (objFolder.Items, i). Если он возвращает ноль или пробел, то у вас есть все заголовки.
Тим Мерфи
@TimMurphy, к сожалению, это неправильно (по крайней мере, в Windows 10 или 7). Некоторые заголовки пусты, поэтому вам нужно перебрать все индексы. (Конечно, поскольку их не миллионы, вы можете ограничить цикл до 1000)
skst
8

Спасибо, ребята, за эту ветку! Это помогло мне, когда я хотел выяснить версию файла exe. Однако мне нужно было самому разобраться в том, что называется расширенными свойствами.

Если вы откроете свойства файла exe (или dll) в проводнике Windows, вы получите вкладку «Версия» и представление дополнительных свойств этого файла. Я хотел получить доступ к одной из этих ценностей.

Решением этой проблемы является индексатор свойств FolderItem.ExtendedProperty, и если вы удалите все пробелы в имени свойства, вы получите значение. Например, версия файла называется FileVersion, и вот она.

Надеюсь, это поможет кому-то еще, просто подумал, что добавлю эту информацию в эту ветку. Ура!

ДЖЕРКЕР
источник
2
Это также гарантирует, что ваш код (по крайней мере, в большинстве случаев) по-прежнему будет работать на машинах, не использующих английский язык.
Эд Норрис
1
Одно небольшое улучшение: FolderItem не содержит ExtendedProperty (). Однако FolderItem2 делает.
Mixxiphoid
Этот ответ немного проще других. Я
привел
8

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);
 }
РаджешКдев
источник
Я скопировал и использовал тот же код, что и выше. Но здесь я получаю исключение COM в runime Folder rFolder = shell.NameSpace(_rootPath);. К вашему сведению, я использую ОС Windows 8.
DonMax
1
Что это за ошибка? Убедитесь, что вы используете правильную версию Shell32.dll. Отметьте это, может быть, полезно
RajeshKdev
1
+1 за ссылку выше. Ссылка, которую вы предложили, работает нормально. Мне нужна еще одна ваша помощь. т.е. как передать один файл для получения метаданных? поскольку он принимает передачу только папки.
DonMax
6
  • После просмотра ряда решений в этом потоке и в других местах был составлен следующий код. Это только для чтения собственности.
  • Мне не удалось заставить работать функцию Shell32.FolderItem2.ExtendedProperty, она должна принимать строковое значение и возвращать правильное значение и тип для этого свойства ... это всегда было пустым для меня, а справочные ресурсы разработчика были очень тонкими.
  • WindowsApiCodePack , похоже, отказались от Microsoft , которая приносит нам код ниже.

Использование:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Вернет вам значение расширенного свойства, которое вы хотите, в виде строки для данного файла и имени свойства.
  2. Выполняет цикл только до тех пор, пока не будет найдено указанное свойство - не до тех пор, пока не будут обнаружены все свойства, как некоторый пример кода
  3. Будет работать в версиях Windows, таких как Windows server 2008, где вы получите ошибку «Невозможно преобразовать COM-объект типа 'System .__ ComObject' в интерфейс типа 'Shell32.Shell'», если просто пытаетесь создать объект Shell32 в обычном режиме.

    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
Обратите внимание, что вместо использования InvokeMember () вы можете shellвыполнить приведение к любому из IShellDispatchинтерфейсов (1-6) и напрямую вызвать член. Shell32.IShellDispatch ishell = (Shell32.IShellDispatch)shell; Shell32.Folder shellFolder = ishell.NameSpace(baseFolder);
skst
5

Ответ Джеркера немного проще. Вот пример кода, который работает от MS :

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

Для тех, кто не может ссылаться на 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.
}
науфал
источник
1

Я не уверен, для каких типов файлов вы пытаетесь написать свойства, но taglib-sharp - отличная библиотека тегов с открытым исходным кодом, которая красиво обертывает всю эту функциональность. Он имеет много встроенной поддержки для большинства популярных типов файлов мультимедиа, но также позволяет выполнять более сложные теги практически для любого файла.

РЕДАКТИРОВАТЬ: я обновил ссылку на taglib sharp. Старая ссылка больше не работала.

РЕДАКТИРОВАТЬ: обновил ссылку еще раз за комментарий kzu.

макет
источник
Это выглядит очень интересно, в основном я буду смотреть видеофайлы (AVI, DIVX и т. Д.). Спасибо за указатель
Дэвид Хейс
Ссылка taglib-sharp кажется мертвой :-( - что странно, поскольку вики на ... developer.novell.com/wiki/index.php/TagLib_Sharp:_Examples ... указывает на этот URL
SteveC
Спасибо, SteveC, в то время, когда я опубликовал эту ссылку, обе ссылки были действительны, и я не был уверен, что было официальным местом, куда можно было бы перейти, похоже, novell - это правильный сайт для этой библиотеки.
mockobject
Спасибо за внимание, kzu, я обновил ссылку в моем исходном ответе, чтобы она также указывала на местоположение github.
mockobject 03
1

Вот решение для чтения, а не записи расширенных свойств, основанное на том, что я нашел на этой странице и в справке по объектам shell32 .

Чтобы было понятно, это взлом. Похоже, этот код по-прежнему будет работать в Windows 10, но затронет некоторые пустые свойства. Предыдущая версия Windows должна использовать:

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

В 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;
    }

Как уже упоминалось, вам необходимо сослаться на сборку Com Interop.Shell32.

Если вы получите исключение, связанное с STA, вы найдете решение здесь:

Исключение при использовании Shell32 для получения расширенных свойств файла

Я понятия не имею, какими будут имена этих свойств в чужой системе, и не мог найти информацию о том, какие локализуемые константы использовать для доступа к словарю. Я также обнаружил, что не все свойства из диалогового окна «Свойства» присутствуют в возвращенном словаре.

Кстати, это ужасно медленно, и - по крайней мере, в Windows 10 - анализ дат в извлеченной строке был бы проблемой, поэтому использование этого кажется плохой идеей для начала.

В Windows 10 вам обязательно нужно использовать библиотеку Windows.Storage, которая содержит SystemPhotoProperties, SystemMusicProperties и т. Д. Https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

И , наконец, я отправил гораздо лучшее решение , которое использует WindowsAPICodePack там

pasx
источник