Lettura / scrittura delle proprietà del file 'estese' (C #)


104

Sto cercando di scoprire come leggere / scrivere nelle proprietà del file estese in C #, ad esempio Commento, Bit Rate, Data di accesso, Categoria ecc. Che puoi vedere in Windows Explorer. Qualche idea su come fare questo? EDIT: leggerò / scriverò principalmente su file video (AVI / DIVX / ...)


3
Questa domanda chiaramente non ha una risposta poiché la risposta accettata mostra solo come ottenere le proprietà estese e non come impostarle .
Dmitri Nesteruk

1
Per impostare le proprietà estese vedere stackoverflow.com/questions/5337683/...
VoteCoffee

Risposte:


83

Per quelli che non vanno matti per VB, eccolo in c #:

Nota, devi aggiungere un riferimento a Microsoft Shell Controls and Automation dalla scheda COM della finestra di dialogo Riferimenti.

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)}");
        }
    }
}

3
come si imposta uno di questi valori? per es. Autore o editore per un file .txt. Sono su Win 7 e ho usato questo e mostra un autore ed editore vuoto e altre 282 proprietà
Vaibhav Garg

1
@Vainbhav - Non puoi impostarli.
csharptest.net

26
È necessario aggiungere un riferimento a Microsoft Shell Controls and Automation dalla scheda COM della finestra di dialogo Refences.
csharptest.net

2
Come impostarli è meglio trattato in questa domanda: stackoverflow.com/questions/5337683/…
Nicolas Raoul

1
In Windows 10 restituisce solo 52 campi esclusi Frame rate, Frame Height, Width, ....?
Minh Nguyen


26

Soluzione 2016

Aggiungi i seguenti pacchetti NuGet al tuo progetto:

  • Microsoft.WindowsAPICodePack-Shell di Microsoft
  • Microsoft.WindowsAPICodePack-Core di Microsoft

Proprietà di lettura e scrittura

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

Importante:

Il file deve essere valido, creato dallo specifico software assegnato. Ogni tipo di file ha proprietà di file estese specifiche e non tutti sono scrivibili.

Se fai clic con il pulsante destro del mouse su un file sul desktop e non puoi modificare una proprietà, non sarai in grado di modificarlo anche nel codice.

Esempio:

  • Crea file txt sul desktop, rinomina la sua estensione in docx. Non puoi modificarne la proprietà Authoro Title.
  • Aprilo con Word, modificalo e salvalo. Ora puoi.

Quindi assicurati di usarne alcuni try catch

Ulteriore argomento: MSDN: implementazione di gestori di proprietà


Non vedo nessun pacchetto con questi nomi da Microsoft
Jacob Brewer

1
@JacobBrewer In realtà è quello che è stato caricato da "acdvorak": nuget.org/packages/Microsoft.WindowsAPICodePack-Shell . In Visual Studio NuGet-Package-Manager viene visualizzato come "da Microsoft". Gli altri pacchetti con nomi simili sono fork di esso e potrebbero anche funzionare correttamente o anche meglio. Non lo so ...
Martin Schneider

25

Questo esempio in VB.NET legge tutte le proprietà estese:

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

È necessario aggiungere un riferimento a Microsoft Shell Controls and Automation dalla scheda COM della finestra di dialogo Riferimenti .


2
Vale la pena notare che su Windows 7 (almeno) è possibile aumentare la dimensione di arrHeaders a poco più di 280 e ottenere molti metadati aggiuntivi. L'ho scoperto quando stavo cercando un modo per ottenere metadati da un file WTV (programma televisivo registrato su Windows 7 Media Center).
Richard

1
Il primo ciclo per i = da 0 a 34 dovrebbe essere per i = 0 su Integer.MaxValue. Quindi verifica il valore restituito di objFolder.GetDetailsOf (objFolder.Items, i). Se restituisce null o spazi vuoti, hai tutte le intestazioni.
Tim Murphy

@TimMurphy, sfortunatamente, non è corretto (almeno su Windows 10 o 7). Alcune intestazioni sono vuote, quindi è necessario scorrere tutti gli indici. (Ovviamente, poiché non ce ne sono milioni, potresti limitare il loop a 1.000.)
skst

8

Grazie ragazzi per questo thread! Mi ha aiutato quando volevo capire la versione del file di un exe. Tuttavia, avevo bisogno di capire da solo l'ultima parte di ciò che viene chiamato Proprietà estese.

Se apri le proprietà di un file exe (o dll) in Esplora risorse, ottieni una scheda Versione e una visualizzazione delle proprietà estese di quel file. Volevo accedere a uno di quei valori.

La soluzione a questo è l'indicizzatore della proprietà FolderItem.ExtendedProperty e se si rilasciano tutti gli spazi nel nome della proprietà, si otterrà il valore. Ad esempio, File Version diventa FileVersion, e il gioco è fatto.

Spero che questo aiuti chiunque altro, ho solo pensato di aggiungere queste informazioni a questo thread. Saluti!


2
Ciò garantisce anche che il tuo codice (almeno per lo più) funzioni ancora su macchine in lingua diversa dall'inglese.
Ed Norris,

1
Un piccolo miglioramento qui, FolderItem non contiene ExtendedProperty (). FolderItem2 invece lo fa.
Mixxiphoid

Questa risposta è un po 'più semplice di altre. Ho dato il codice di esempio che funziona qui: stackoverflow.com/a/46648086/661933
Nawfal

8

GetDetailsOf()Metodo: recupera i dettagli su un elemento in una cartella. Ad esempio, le sue dimensioni, il tipo o l'ora dell'ultima modifica. Le proprietà del file possono variare in base alla Windows-OSversione.

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

Ho copiato e utilizzato lo stesso codice sopra. Ma sto ricevendo un'eccezione COM in fase di esecuzione qui Folder rFolder = shell.NameSpace(_rootPath);. Cordiali saluti, sto usando il sistema operativo Windows 8.
DonMax

1
Cos'è questo errore? Assicurati di utilizzare la versione corretta di Shell32.dll. Controlla questo
potrebbe essere

1
+1 per il link sopra. Il collegamento che hai suggerito funziona correttamente. Ho bisogno di un altro aiuto da te. cioè, come posso passare il singolo file per ottenere i metadati ?? poiché accetta di passare solo la cartella.
DonMax

6
  • Dopo aver esaminato una serie di soluzioni su questo thread e altrove, è stato messo insieme il codice seguente. Questo è solo per leggere una proprietà.
  • Non sono riuscito a far funzionare la funzione Shell32.FolderItem2.ExtendedProperty, si suppone che prenda un valore stringa e restituisca il valore e il tipo corretti per quella proprietà ... questo era sempre nullo per me e le risorse di riferimento per gli sviluppatori erano molto scarse.
  • Il WindowsApiCodePack sembra essere stato abbandonato da Microsoft che ci porta il codice qui sotto.

Uso:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Ti restituirà il valore della proprietà estesa che desideri come stringa per il file e il nome della proprietà specificati.
  2. Esegue il ciclo solo finché non trova la proprietà specificata, non finché tutte le proprietà non vengono scoperte come un codice di esempio
  3. Funzionerà su versioni di Windows come Windows Server 2008, dove riceverai l'errore "Impossibile eseguire il cast di un oggetto COM di tipo" System .__ ComObject "nel tipo di interfaccia" Shell32.Shell "" se si tenta di creare normalmente l'oggetto 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
Si noti che invece di utilizzare InvokeMember () , è possibile eseguire il cast shellsu una qualsiasi delle IShellDispatchinterfacce (1-6) e chiamare direttamente il membro. Shell32.IShellDispatch ishell = (Shell32.IShellDispatch)shell; Shell32.Folder shellFolder = ishell.NameSpace(baseFolder);
skst

5

La risposta di Jerker è un po 'più semplice. Ecco un esempio di codice che funziona da MS :

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

Per coloro che non possono fare riferimento staticamente a shell32, puoi invocarlo dinamicamente in questo modo:

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

Non sono sicuro di quali tipi di file stai cercando di scrivere le proprietà, ma taglib-sharp è un'eccellente libreria di tag open source che racchiude bene tutte queste funzionalità. Ha un sacco di supporto integrato per la maggior parte dei tipi di file multimediali più diffusi, ma ti consente anche di eseguire tag più avanzati praticamente con qualsiasi file.

EDIT: ho aggiornato il collegamento a taglib sharp. Il vecchio collegamento non funzionava più.

EDIT: aggiornato ancora una volta il collegamento per il commento di kzu.


Sembra molto interessante, guarderò principalmente i file video (AVI, DIVX ecc.). Grazie per il puntatore
David Hayes,

Il collegamento taglib-sharp sembra essere morto :-( - che è strano come il wiki su ... developer.novell.com/wiki/index.php/TagLib_Sharp:_Examples ... punta a
quell'URL

Grazie, SteveC, nel momento in cui ho pubblicato questo entrambi i link erano validi e non ero sicuro di quale fosse il posto ufficiale dove andare, sembra che novell sia il sito giusto dove andare per questa libreria ora.
mockobject

Grazie per l'avviso kzu, ho aggiornato il collegamento nella mia risposta originale per indicare anche la posizione di github.
mockobject

1

Ecco una soluzione per leggere - non scrivere - le proprietà estese in base a ciò che ho trovato in questa pagina e in aiuto con gli oggetti shell32 .

Per essere chiari questo è un trucco. Sembra che questo codice funzionerà ancora su Windows 10 ma colpirà alcune proprietà vuote. La versione precedente di Windows dovrebbe utilizzare:

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

Su Windows 10 presumiamo che ci siano circa 320 proprietà da leggere e saltiamo semplicemente le voci vuote:

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

Come accennato, è necessario fare riferimento all'assembly Com Interop.Shell32.

Se ricevi un'eccezione relativa a STA, troverai la soluzione qui:

Eccezione quando si utilizza Shell32 per ottenere le proprietà estese del file

Non ho idea di come sarebbero i nomi di queste proprietà su un sistema esterno e non sono riuscito a trovare informazioni su quali costanti localizzabili utilizzare per accedere al dizionario. Ho anche scoperto che non tutte le proprietà della finestra di dialogo Proprietà erano presenti nel dizionario restituito.

A proposito, questo è terribilmente lento e, almeno su Windows 10, l'analisi delle date nella stringa recuperata sarebbe una sfida, quindi l'utilizzo di questo sembra essere una cattiva idea con cui iniziare.

Su Windows 10 dovresti assolutamente usare la libreria Windows.Storage che contiene SystemPhotoProperties, SystemMusicProperties ecc. Https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

E infine, ho pubblicato una soluzione molto migliore che utilizza WindowsAPICodePack

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.