Baca / Tulis properti file 'Diperluas' (C #)

104

Saya mencoba mencari cara untuk membaca / menulis ke properti file yang diperluas di C # misalnya Komentar, Bit Rate, Tanggal Diakses, Kategori dll yang dapat Anda lihat di Windows explorer. Ada ide bagaimana melakukan ini? EDIT: Saya terutama akan membaca / menulis ke file video (AVI / DIVX / ...)

David Hayes
sumber
3
Pertanyaan ini jelas tidak terjawab karena jawaban yang diterima hanya menunjukkan bagaimana mendapatkan properti yang diperluas dan bukan bagaimana mengaturnya .
Dmitri Nesteruk
1
Untuk menyetel properti yang diperluas lihat stackoverflow.com/questions/5337683/…
VoteCoffee

Jawaban:

83

Bagi mereka yang tidak tergila-gila dengan VB, ini dia di c #:

Catatan, Anda harus menambahkan referensi ke Microsoft Shell Controls and Automation dari tab COM pada dialog Referensi.

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
sumber
3
bagaimana cara menetapkan salah satu dari nilai-nilai ini? untuk misalnya Penulis atau penerbit untuk file .txt. Saya menang 7 dan menggunakan ini dan ini menunjukkan penulis dan penerbit kosong dan 282 properti lainnya
Vaibhav Garg
1
@Vainbhav - Anda tidak dapat mengatur ini.
csharptest.net
26
Anda harus menambahkan referensi ke Microsoft Shell Controls and Automation dari tab COM pada dialog Refences.
csharptest.net
2
Bagaimana mengaturnya lebih baik dibahas dalam pertanyaan ini: stackoverflow.com/questions/5337683/…
Nicolas Raoul
1
Di Windows 10 itu hanya mengembalikan 52 bidang tidak termasuk Frame rate, Frame Height, Width, ....?
Minh Nguyen
27

Ada artikel CodeProject untuk pembaca ID3. Dan utas di kixtart.org yang memiliki lebih banyak informasi untuk properti lainnya. Pada dasarnya, Anda perlu memanggil GetDetailsOf()metode pada objek shell folder untuk shell32.dll.

Mark Cidade
sumber
Terima kasih, saya harus dapat mengumpulkan apa yang saya butuhkan dari ini
David Hayes
26

Solusi 2016

Tambahkan paket NuGet berikut ke proyek Anda:

  • Microsoft.WindowsAPICodePack-Shell oleh Microsoft
  • Microsoft.WindowsAPICodePack-Core oleh Microsoft

Membaca dan Menulis Properti

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

Penting:

File tersebut harus yang valid, dibuat oleh perangkat lunak tertentu yang ditugaskan. Setiap jenis file memiliki properti file tambahan tertentu dan tidak semuanya dapat ditulis.

Jika Anda mengklik kanan file di desktop dan tidak dapat mengedit properti, Anda juga tidak dapat mengeditnya dalam kode.

Contoh:

  • Buat file txt di desktop, ganti nama ekstensinya menjadi docx. Anda tidak dapat mengedit Authoratau Titlepropertinya.
  • Buka dengan Word, edit dan simpan. Sekarang kamu bisa.

Jadi pastikan untuk menggunakan beberapa try catch

Topik Lebih Lanjut: MSDN: Menerapkan Penangan Properti

Martin Schneider
sumber
Saya tidak melihat paket apa pun dengan nama ini dari Microsoft
Jacob Brewer
1
@JacobBrewer Ini sebenarnya yang diunggah oleh "acdvorak": nuget.org/packages/Microsoft.WindowsAPICodePack-Shell . Dalam Visual Studio NuGet-Package-Manager itu ditampilkan sebagai "oleh Microsoft". Paket lain dengan nama yang mirip adalah percabangannya dan mungkin juga berfungsi dengan baik atau bahkan lebih baik. Saya tidak tahu ...
Martin Schneider
25

Contoh di VB.NET ini membaca semua properti yang diperluas:

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

Anda harus menambahkan referensi ke Microsoft Shell Controls and Automation dari tab COM pada dialog Referensi .

Dirk Vollmar
sumber
2
Perlu dicatat bahwa pada Windows 7 (setidaknya) Anda dapat meningkatkan ukuran arrHeaders menjadi lebih dari 280 dan mendapatkan kembali banyak meta-data tambahan. Saya menemukan ini ketika saya sedang mencari cara untuk mendapatkan meta-data dari file WTV (rekaman acara televisi Windows 7 Media Center).
Richard
1
Pertama untuk loop i = 0 hingga 34 harus untuk i = 0 ke Integer.MaxValue. Kemudian uji nilai kembali dari objFolder.GetDetailsOf (objFolder.Items, i). Jika mengembalikan kosong atau spasi spasi maka Anda memiliki semua header.
Tim Murphy
@TimMurphy, sayangnya, itu tidak benar (setidaknya di Windows 10 atau 7). Beberapa header kosong, jadi Anda perlu mengulang melalui semua indeks. (Tentu saja, karena jumlahnya tidak jutaan, Anda dapat membatasi loop menjadi 1.000.)
skst
8

Terima kasih teman-teman untuk utas ini! Ini membantu saya ketika saya ingin mengetahui versi file exe. Namun, saya perlu mencari tahu bagian terakhir dari apa yang disebut Extended Properties.

Jika Anda membuka properti file exe (atau dll) di Windows Explorer, Anda mendapatkan tab Versi, dan tampilan Extended Properties dari file itu. Saya ingin mengakses salah satu nilai itu.

Solusi untuk ini adalah pengindeks properti FolderItem.ExtendedProperty dan jika Anda menghapus semua spasi di nama properti, Anda akan mendapatkan nilainya. Misalnya Versi File menjadi FileVersion, dan begitulah.

Semoga ini bisa membantu orang lain, saya pikir saya akan menambahkan info ini ke utas ini. Bersulang!

JERKER
sumber
2
Ini juga memastikan bahwa kode Anda (setidaknya sebagian besar) akan tetap berfungsi di mesin berbahasa non-Inggris.
Ed Norris
1
Satu perbaikan kecil di sini, FolderItem tidak berisi ExtendedProperty (). FolderItem2 tidak.
Mixxiphoid
Jawaban ini sedikit lebih sederhana dari yang lain. Saya telah memberikan kode contoh yang berfungsi di sini: stackoverflow.com/a/46648086/661933
nawfal
8

GetDetailsOf()Metode - Mengambil detail tentang item di folder. Misalnya, ukuran, jenis, atau waktu modifikasi terakhirnya. Properti File mungkin berbeda berdasarkan Windows-OSversinya.

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
sumber
Saya telah menyalin dan menggunakan kode yang sama di atas. Tapi, saya mendapatkan pengecualian COM saat runime di sini Folder rFolder = shell.NameSpace(_rootPath);. FYI, saya menggunakan OS Windows 8.
DonMax
1
Apa kesalahan itu? Pastikan Anda menggunakan versi Shell32.dll yang benar. Periksa ini mungkin Berguna
RajeshKdev
1
1 untuk tautan di atas. Tautan yang Anda sarankan berfungsi dengan baik. Saya butuh satu bantuan lagi dari Anda. yaitu, Bagaimana cara melewatkan file tunggal untuk mendapatkan metadata ?? karena, menerima hanya lewat folder.
DonMax
6
  • Setelah melihat sejumlah solusi di utas ini dan di tempat lain, kode berikut disatukan. Ini hanya untuk membaca properti.
  • Saya tidak bisa mendapatkan fungsi Shell32.FolderItem2.ExtendedProperty untuk bekerja, itu seharusnya mengambil nilai string dan mengembalikan nilai dan jenis yang benar untuk properti itu ... ini selalu nol untuk saya dan sumber referensi pengembang sangat tipis.
  • The WindowsApiCodePack tampaknya telah ditinggalkan oleh Microsoft yang membawa kita kode di bawah ini.

Menggunakan:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Akan mengembalikan Anda nilai properti yang diperluas yang Anda inginkan sebagai string untuk file dan nama properti yang diberikan.
  2. Hanya mengulang hingga menemukan properti yang ditentukan - tidak hingga semua properti ditemukan seperti beberapa kode contoh
  3. Akan bekerja pada versi Windows seperti Windows server 2008 di mana Anda akan mendapatkan kesalahan "Tidak dapat mentransmisikan objek COM jenis 'System .__ ComObject' ke tipe antarmuka 'Shell32.Shell'" jika hanya mencoba membuat Objek Shell32 secara normal.

    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
sumber
1
Perhatikan bahwa alih-alih menggunakan InvokeMember () , Anda dapat mentransmisikan shellke salah satu IShellDispatchantarmuka (1-6) dan memanggil anggota secara langsung. Shell32.IShellDispatch ishell = (Shell32.IShellDispatch)shell; Shell32.Folder shellFolder = ishell.NameSpace(baseFolder);
skst
5

Jawaban Jerker sedikit lebih sederhana. Berikut kode contoh yang bekerja dari MS :

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

Bagi mereka yang tidak dapat mereferensikan shell32 secara statis, Anda dapat memanggilnya secara dinamis seperti ini:

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
sumber
1

Saya tidak yakin jenis file apa yang Anda coba tulis propertinya tetapi taglib-sharp adalah pustaka penandaan sumber terbuka yang sangat baik yang membungkus semua fungsi ini dengan baik. Ini memiliki banyak dukungan bawaan untuk sebagian besar jenis file media populer tetapi juga memungkinkan Anda untuk melakukan penandaan lebih lanjut dengan hampir semua file.

EDIT: Saya telah memperbarui tautan ke taglib sharp. Tautan lama tidak lagi berfungsi.

EDIT: Memperbarui tautan sekali lagi per komentar kzu.

mockobject
sumber
Ini terlihat sangat menarik, saya terutama akan melihat file video (AVI, DIVX dll). Terima kasih atas penunjuknya
David Hayes
Tautan tajam-taglib sepertinya sudah mati :-( - yang aneh seperti wiki di ... developer.novell.com/wiki/index.php/TagLib_Sharp:_Contoh ... menunjuk ke URL itu
SteveC
Terima kasih, SteveC, pada saat saya memposting ini, kedua tautan itu valid dan saya tidak yakin mana tempat resminya, sepertinya novell adalah situs yang tepat untuk dikunjungi untuk lib ini sekarang.
mockobject
Terima kasih atas perhatiannya kzu, saya telah memperbarui tautan dalam jawaban asli saya untuk menunjuk ke lokasi github juga.
mockobject
1

Berikut adalah solusi untuk membaca - bukan menulis - properti yang diperluas berdasarkan apa yang saya temukan di halaman ini dan dengan bantuan objek shell32 .

Untuk memperjelas ini adalah retasan. Sepertinya kode ini masih akan berjalan di Windows 10 tetapi akan mengenai beberapa properti kosong. Versi Windows sebelumnya harus menggunakan:

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

Di Windows 10 kami berasumsi bahwa ada sekitar 320 properti untuk dibaca dan cukup lewati entri kosong:

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

Seperti yang disebutkan, Anda perlu merujuk pada perakitan Com Interop.Shell32.

Jika Anda mendapatkan pengecualian terkait STA, Anda akan menemukan solusinya di sini:

Pengecualian saat menggunakan Shell32 untuk mendapatkan properti file diperpanjang

Saya tidak tahu seperti apa nama properti itu pada sistem asing dan tidak dapat menemukan informasi tentang konstanta yang dapat dilokalkan yang akan digunakan untuk mengakses kamus. Saya juga menemukan bahwa tidak semua properti dari dialog Properti yang ada di kamus dikembalikan.

BTW ini sangat lambat dan - setidaknya pada Windows 10 - penguraian tanggal dalam string yang diambil akan menjadi tantangan sehingga menggunakan ini tampaknya ide yang buruk untuk memulai.

Pada Windows 10 Anda pasti harus menggunakan pustaka Windows.Storage yang berisi SystemPhotoProperties, SystemMusicProperties, dll. Https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

Dan akhirnya, saya memposting solusi yang jauh lebih baik yang menggunakan WindowsAPICodePack di sana

pasx
sumber