Lesen / Schreiben von 'erweiterten' Dateieigenschaften (C #)

104

Ich versuche herauszufinden, wie man die erweiterten Dateieigenschaften in C # liest / schreibt, z. B. Kommentar, Bitrate, Zugriffsdatum, Kategorie usw., die Sie im Windows Explorer sehen können. Irgendwelche Ideen, wie das geht? EDIT: Ich werde hauptsächlich Videodateien lesen / schreiben (AVI / DIVX / ...)

David Hayes
quelle
3
Diese Frage wird eindeutig nicht beantwortet, da die akzeptierte Antwort nur zeigt, wie die erweiterten Eigenschaften abgerufen und nicht festgelegt werden .
Dmitri Nesteruk
1
Informationen
VoteCoffee

Antworten:

83

Für diejenigen, die nicht verrückt nach VB sind, hier ist es in c #:

Beachten Sie, dass Sie auf der Registerkarte COM des Dialogfelds Referenzen einen Verweis auf Microsoft Shell Controls and Automation hinzufügen müssen .

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
quelle
3
Wie würde man einen dieser Werte einstellen? für zB Autor oder Herausgeber für eine TXT-Datei. Ich bin auf Win 7 und habe dies verwendet und es zeigt einen leeren Autor und Herausgeber und 282 andere Eigenschaften
Vaibhav Garg
1
@Vainbhav - Sie können diese nicht einstellen.
csharptest.net
26
Sie müssen auf der Registerkarte COM des Dialogfelds Refences einen Verweis auf Microsoft Shell Controls and Automation hinzufügen.
csharptest.net
2
Wie man sie einstellt
Nicolas Raoul
1
In Windows 10 werden nur 52 Felder ohne Bildrate, Bildhöhe, Breite, ... zurückgegeben.
Minh Nguyen
27

Es gibt einen CodeProject-Artikel für einen ID3-Reader. Und ein Thread auf kixtart.org , der weitere Informationen für andere Eigenschaften enthält. Grundsätzlich müssen Sie die GetDetailsOf()Methode für das Ordner- Shell-Objekt für aufrufen shell32.dll.

Mark Cidade
quelle
Danke, ich sollte in der Lage sein, das zusammenzubringen, was ich brauche
David Hayes
26

Lösung 2016

Fügen Sie Ihrem Projekt folgende NuGet-Pakete hinzu:

  • Microsoft.WindowsAPICodePack-Shell von Microsoft
  • Microsoft.WindowsAPICodePack-Core von Microsoft

Lese- und Schreibeigenschaften

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

Wichtig:

Die Datei muss gültig sein und von der zugewiesenen Software erstellt werden. Jeder Dateityp verfügt über bestimmte erweiterte Dateieigenschaften, von denen nicht alle beschreibbar sind.

Wenn Sie mit der rechten Maustaste auf eine Datei auf dem Desktop klicken und eine Eigenschaft nicht bearbeiten können, können Sie sie auch nicht im Code bearbeiten.

Beispiel:

  • Erstellen Sie eine txt-Datei auf dem Desktop und benennen Sie ihre Erweiterung in docx um. Sie können seine Authoroder TitleEigenschaft nicht bearbeiten .
  • Öffnen Sie es mit Word, bearbeiten und speichern Sie es. Jetzt kannst du.

Stellen Sie also sicher, dass Sie einige verwenden try catch

Weiteres Thema: MSDN: Implementieren von Property Handlern

Martin Schneider
quelle
Ich sehe keine Pakete mit diesen Namen von Microsoft
Jacob Brewer
1
@JacobBrewer Es ist tatsächlich dasjenige, das von "acdvorak" hochgeladen wurde: nuget.org/packages/Microsoft.WindowsAPICodePack-Shell . In Visual Studio NuGet-Package-Manager wird es als "von Microsoft" angezeigt. Die anderen Pakete mit ähnlichen Namen sind Gabeln davon und könnten auch richtig oder sogar besser funktionieren. Ich weiß nicht ...
Martin Schneider
25

Dieses Beispiel in VB.NET liest alle erweiterten Eigenschaften:

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

Sie müssen auf der Registerkarte COM des Dialogfelds Referenzen einen Verweis auf Microsoft Shell Controls and Automation hinzufügen .

Dirk Vollmar
quelle
2
Es ist erwähnenswert, dass Sie unter Windows 7 (zumindest) die Größe von arrHeaders auf etwas mehr als 280 erhöhen und viele zusätzliche Metadaten zurückerhalten können. Ich fand dies heraus, als ich nach einer Möglichkeit suchte, Metadaten aus einer WTV-Datei (Windows 7 Media Center aufgezeichnete Fernsehsendung) abzurufen.
Richard
1
Die erste Schleife für i = 0 bis 34 sollte für i = 0 bis Integer.MaxValue sein. Testen Sie dann den Rückgabewert von objFolder.GetDetailsOf (objFolder.Items, i). Wenn es null oder Leerzeichen zurückgibt, haben Sie alle Header.
Tim Murphy
@ TimMurphy ist leider nicht korrekt (zumindest unter Windows 10 oder 7). Einige Header sind leer, daher müssen Sie alle Indizes durchlaufen. (Da es nicht Millionen von ihnen gibt, können Sie die Schleife
natürlich
8

Vielen Dank für diesen Thread! Es hat mir geholfen, als ich die Dateiversion einer Exe herausfinden wollte. Ich musste jedoch selbst das letzte Stück der sogenannten erweiterten Eigenschaften herausfinden.

Wenn Sie die Eigenschaften einer exe- (oder DLL-) Datei im Windows Explorer öffnen, erhalten Sie eine Registerkarte Version und eine Ansicht der erweiterten Eigenschaften dieser Datei. Ich wollte auf einen dieser Werte zugreifen.

Die Lösung hierfür ist der Eigenschaftsindexer FolderItem.ExtendedProperty. Wenn Sie alle Leerzeichen im Namen der Eigenschaft löschen, erhalten Sie den Wert. ZB geht die Dateiversion zu FileVersion, und da haben Sie es.

Hoffe, das hilft anderen, dachte nur, ich würde diese Informationen zu diesem Thread hinzufügen. Prost!

JERKER
quelle
2
Dies stellt auch sicher, dass Ihr Code (zumindest meistens) auch auf nicht englischsprachigen Computern funktioniert.
Ed Norris
1
Eine kleine Verbesserung ist, dass FolderItem ExtendedProperty () nicht enthält. FolderItem2 tut dies jedoch.
Mixxiphoid
Diese Antwort ist etwas einfacher als andere. Ich habe Beispielcode gegeben, der hier funktioniert: stackoverflow.com/a/46648086/661933
nawfal
8

GetDetailsOf()Methode - Ruft Details zu einem Element in einem Ordner ab. Zum Beispiel seine Größe, sein Typ oder der Zeitpunkt seiner letzten Änderung. Die Dateieigenschaften können je nach Windows-OSVersion variieren .

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);
 }
RajeshKdev
quelle
Ich habe den gleichen Code wie oben kopiert und verwendet. Aber ich bekomme hier zur Laufzeit eine COM-Ausnahme Folder rFolder = shell.NameSpace(_rootPath);. Zu Ihrer Information, ich verwende Windows 8.
DonMax
1
Was ist das für ein Fehler? Stellen Sie sicher, dass Sie die richtige Version von Shell32.dll verwenden. Überprüfen Sie dies vielleicht nützlich
RajeshKdev
1
+1 für den obigen Link. Der von Ihnen vorgeschlagene Link funktioniert einwandfrei. Ich brauche noch eine Hilfe von dir. dh wie kann ich die einzelne Datei übergeben, um die Metadaten zu erhalten? da akzeptiert es nur den Ordner zu übergeben.
DonMax
6
  • Nach einer Reihe von Lösungen in diesem Thread und anderswo wurde der folgende Code zusammengestellt. Dies dient nur zum Lesen einer Eigenschaft.
  • Ich konnte die Shell32.FolderItem2.ExtendedProperty-Funktion nicht zum Laufen bringen. Sie sollte einen Zeichenfolgenwert annehmen und den korrekten Wert und Typ für diese Eigenschaft zurückgeben. Dies war für mich immer null und die Entwicklerreferenzressourcen waren sehr dünn.
  • Das WindowsApiCodePack scheint von Microsoft aufgegeben worden zu sein, was uns den folgenden Code bringt.

Verwenden:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Gibt Ihnen den Wert der gewünschten erweiterten Eigenschaft als Zeichenfolge für die angegebene Datei und den angegebenen Eigenschaftsnamen zurück.
  2. Nur Schleifen, bis die angegebene Eigenschaft gefunden wurde - nicht bis alle Eigenschaften wie ein Beispielcode erkannt wurden
  3. Funktioniert unter Windows-Versionen wie Windows Server 2008, bei denen die Fehlermeldung "COM-Objekt vom Typ 'System .__ ComObject' kann nicht in den Schnittstellentyp 'Shell32.Shell' umgewandelt werden" angezeigt wird, wenn nur versucht wird, das Shell32-Objekt normal zu erstellen.

    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;
    }
Rohan
quelle
1
Beachten Sie, dass anstelle der Verwendung InvokeMember () , Sie werfen kann shelleinem der IShellDispatchSchnittstellen (1-6) und das Mitglied direkt anrufen. Shell32.IShellDispatch ishell = (Shell32.IShellDispatch)shell; Shell32.Folder shellFolder = ishell.NameSpace(baseFolder);
Skst
5

Jerkers Antwort ist etwas einfacher. Hier ist ein Beispielcode, der von MS aus funktioniert :

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

Für diejenigen, die Shell32 nicht statisch referenzieren können, können Sie es dynamisch wie folgt aufrufen:

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.
}
nawfal
quelle
1

Ich bin nicht sicher, für welche Dateitypen Sie die Eigenschaften schreiben möchten, aber taglib-scharf ist eine hervorragende Open-Source-Tagging-Bibliothek, die all diese Funktionen gut zusammenfasst. Es bietet eine Menge integrierter Unterstützung für die meisten gängigen Mediendateitypen, ermöglicht Ihnen jedoch auch das erweiterte Taggen mit nahezu jeder Datei.

BEARBEITEN: Ich habe den Link zu Taglib Sharp aktualisiert. Der alte Link funktionierte nicht mehr.

BEARBEITEN: Der Link wurde gemäß dem Kommentar von kzu noch einmal aktualisiert.

Scheinobjekt
quelle
Das sieht sehr interessant aus, ich werde mich hauptsächlich mit Videodateien (AVI, DIVX usw.) befassen. Vielen Dank für den
David Hayes
Der taglib-scharfe Link scheint tot zu sein :-( - was seltsam ist, da das Wiki unter ... developer.novell.com/wiki/index.php/TagLib_Sharp:_Examples ... auf diese URL verweist
SteveC
Vielen Dank, SteveC, als ich dies gepostet habe, waren beide Links gültig und ich war mir nicht sicher, welcher der offizielle Ort war. Es sieht so aus, als ob Novell jetzt die richtige Seite für diese Bibliothek ist.
Mockobject
Vielen Dank für das Heads-up-Kzu. Ich habe den Link in meiner ursprünglichen Antwort aktualisiert, um auch auf den Github-Standort zu verweisen.
Mockobject
1

Hier ist eine Lösung zum Lesen und nicht zum Schreiben der erweiterten Eigenschaften, basierend auf dem, was ich auf dieser Seite gefunden habe, und Hilfe bei Shell32-Objekten .

Um klar zu sein, ist dies ein Hack. Es sieht so aus, als würde dieser Code unter Windows 10 weiterhin ausgeführt, trifft jedoch auf einige leere Eigenschaften. In früheren Windows-Versionen sollte Folgendes verwendet werden:

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

Unter Windows 10 gehen wir davon aus, dass etwa 320 Eigenschaften gelesen werden müssen, und überspringen einfach die leeren Einträge:

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

Wie bereits erwähnt, müssen Sie auf die Com-Assembly Interop.Shell32 verweisen.

Wenn Sie eine STA-bezogene Ausnahme erhalten, finden Sie die Lösung hier:

Ausnahme bei Verwendung von Shell32 zum Abrufen der erweiterten Dateieigenschaften

Ich habe keine Ahnung, wie diese Eigenschaftsnamen auf einem fremden System aussehen würden, und konnte keine Informationen darüber finden, welche lokalisierbaren Konstanten für den Zugriff auf das Wörterbuch verwendet werden sollen. Ich habe auch festgestellt, dass nicht alle Eigenschaften aus dem Dialogfeld "Eigenschaften" im zurückgegebenen Wörterbuch vorhanden waren.

Übrigens ist dies furchtbar langsam und - zumindest unter Windows 10 - das Parsen von Daten in der abgerufenen Zeichenfolge wäre eine Herausforderung. Daher scheint es zunächst eine schlechte Idee zu sein, dies zu verwenden.

Unter Windows 10 sollten Sie auf jeden Fall die Windows.Storage-Bibliothek verwenden, die die SystemPhotoProperties, SystemMusicProperties usw. enthält. Https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

Und schließlich gab ich eine viel bessere Lösung , dass Verwendungen WindowsAPICodePack dort

pasx
quelle