Чтение / запись расширенных свойств файла (C#)
Я пытаюсь выяснить, как читать / записывать расширенные свойства файла в C#, например, Комментарий, Битрейт, Дата обращения, Категория и т. Д., Которые вы можете увидеть в проводнике Windows. Есть идеи, как это сделать? РЕДАКТИРОВАТЬ: я буду в основном читать / писать в видео файлы (AVI/DIVX/...)
9 ответов
Для тех, кто не без ума от VB, вот он в C#:
Обратите внимание, что вы должны добавить ссылку на Microsoft Shell Controls and Automation на вкладке COM диалогового окна "Ссылки".
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)}");
}
}
}
Решение 2016
Добавьте следующие пакеты NuGet в свой проект:
Microsoft.WindowsAPICodePack-Shell
MicrosoftMicrosoft.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: Реализация обработчиков свойств
Есть статья CodeProject для читателя ID3. И поток на kixtart.org, который имеет больше информации для других свойств. В основном вам нужно позвонить GetDetailsOf()
Метод объекта оболочки папки для shell32.dll
,
Этот пример в 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 диалогового окна " Ссылки ".
Спасибо ребята за эту ветку! Это помогло мне, когда я хотел выяснить версию файла exe. Тем не менее, мне нужно было выяснить сам последний из того, что называется расширенными свойствами.
Если вы откроете свойства exe (или dll) файла в Windows Explorer, вы получите вкладку Version и просмотр расширенных свойств этого файла. Я хотел получить доступ к одному из этих значений.
Решением этой проблемы является индексатор свойства FolderItem.ExtendedProperty, и если вы удалите все пробелы в имени свойства, вы получите значение. Например, версия файла идет FileVersion, и там у вас есть.
Надеюсь, это кому-нибудь еще поможет, просто подумал, что я добавлю эту информацию в эту ветку. Ура!
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);
}
Ответ Джеркера немного проще. Вот пример кода, который работает от 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.
}
- Посмотрев на ряд решений в этой теме и в других местах, был составлен следующий код. Это только для чтения собственности.
- Я не смог заставить работать функцию Shell32.FolderItem2.ExtendedProperty, она должна принимать строковое значение и возвращать правильное значение и тип для этого свойства... это всегда было для меня нулевым, а справочные ресурсы разработчика были очень тонкими.
- WindowsApiCodePack, похоже, был заброшен Microsoft, что дает нам код ниже.
Использование:
string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
- Вернет вам значение расширенного свойства, которое вы хотите, в виде строки для данного файла и имени свойства.
- Только зацикливается, пока не найдет указанное свойство, - пока все свойства не будут обнаружены, как пример кода
Будет работать на версиях 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; }
Вот решение для чтения - не записи - расширенных свойств, основанное на том, что я нашел на этой странице и в справке по объектам 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 там
Я не уверен, для каких типов файлов вы пытаетесь написать свойства, но taglib-sharp - отличная библиотека тегов с открытым исходным кодом, которая прекрасно сочетает в себе всю эту функциональность. Он имеет встроенную поддержку для большинства популярных типов медиа-файлов, но также позволяет выполнять более сложные теги практически для любого файла.
РЕДАКТИРОВАТЬ: Я обновил ссылку на Taglib Sharp. Старая ссылка больше не работает.
РЕДАКТИРОВАТЬ: Обновил ссылку еще раз для комментария кзу.