web-dev-qa-db-ja.com

「拡張」ファイルプロパティの読み取り/書き込み(C#)

私はC#で拡張ファイルのプロパティを読み書きする方法を見つけようとしていますコメント、ビットレート、アクセス日、カテゴリなど、Windowsエクスプローラーで確認できます。これを行う方法はありますか?編集:私は主にビデオファイル(AVI/DIVX/...)を読み書きします

96
David Hayes

VBに夢中ではない人のために、C#にあります:

[参照]ダイアログの[COM]タブからMicrosoft Shell Controls and Automationへの参照を追加する必要があります。

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)}");
        }
    }
}
79
csharptest.net

ID3リーダーには CodeProjectの記事 があります。 kixtart.orgのスレッド には、他のプロパティの詳細情報が含まれています。基本的に、Shell32.dllfolderShellオブジェクトで GetDetailsOf() method を呼び出す必要があります。

27
Mark Cidade

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タブから参照を追加する必要があります。ダイアログ。

25
Dirk Vollmar

ソリューション2016

次のNuGetパッケージをプロジェクトに追加します。

  • Microsoft.WindowsAPICodePack-Shell by Microsoft
  • Microsoft.WindowsAPICodePack-Core by 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で開き、編集して保存します。今できます。

したがって、必ずtrycatchを使用してください。

さらなるトピック: MSDN:プロパティハンドラーの実装

23

このスレッドをありがとう。 exeのファイルバージョンを把握したいときに役立ちました。ただし、拡張プロパティと呼ばれるものの最後の部分を自分で把握する必要がありました。

Windowsエクスプローラーでexe(またはdll)ファイルのプロパティを開くと、[バージョン]タブと、そのファイルの拡張プロパティのビューが表示されます。これらの値の1つにアクセスしたかった。

これに対する解決策は、プロパティインデクサーFolderItem.ExtendedPropertyです。プロパティの名前に含まれるすべてのスペースを削除すると、値が取得されます。例えば。 File VersionはFileVersionになり、そこにあります。

これが他の誰にも役立つことを願っています。このスレッドにこの情報を追加すると思いました。乾杯!

8
JERKER

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

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

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.
}
5
nawfal
  • このスレッドや他の場所で多くのソリューションを検討した後、次のコードがまとめられました。これは、プロパティを読み取るためだけです。
  • Shell32.FolderItem2.ExtendedProperty関数を動作させることができませんでした。文字列値を取得し、そのプロパティの正しい値と型を返すことになっています。
  • WindowsApiCodePack はMicrosoftによって放棄されたようで、以下のコードが表示されます。

つかいます:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. 指定したファイルとプロパティ名の文字列として、必要な拡張プロパティの値を返します。
  2. 指定したプロパティが見つかるまでループします。サンプルコードのようにすべてのプロパティが見つかるまでループしません。
  3. エラーが発生するWindowsサーバー2008などのWindowsバージョンで動作します "タイプ 'System .__ ComObject'のCOMオブジェクトをインターフェイスタイプ '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;
    }
    
4
Rohan

どのタイプのファイルでプロパティを記述しようとしているのかわかりませんが、 taglib-sharp は、このすべての機能をうまくまとめた優れたオープンソースのタグ付けライブラリです。人気のあるほとんどのメディアファイルタイプのサポートが組み込まれていますが、ほぼすべてのファイルでより高度なタグ付けを行うこともできます。

EDIT:taglib sharpへのリンクを更新しました。古いリンクは機能しなくなりました。

EDIT:kzuのコメントごとにリンクをもう一度更新しました。

1
mockobject

このページと 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 Assembly Interop.Shell32を参照する必要があります。

STA関連の例外が発生した場合は、次のソリューションを見つけることができます。

Shell32を使用してファイルの拡張プロパティを取得する場合の例外

これらのプロパティ名が外部システムでどのようなものになるのか分かりませんし、辞書にアクセスするために使用するローカライズ可能な定数に関する情報を見つけることができませんでした。また、返された辞書に、[プロパティ]ダイアログのすべてのプロパティが存在するわけではないこともわかりました。

ところで、これは非常に遅く、少なくともWindows 10では、取得された文字列の日付の解析は難しいので、これを使用することは最初から悪い考えのようです。

Windows 10では、SystemPhotoProperties、SystemMusicPropertiesなどを含むWindows.Storageライブラリを必ず使用する必要があります。 https://docs.Microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-プロパティ

そして最後に、WindowsAPICodePackを使用するはるかに優れたソリューションを投稿しました あり

0
pasx