อ่าน / เขียนคุณสมบัติไฟล์ 'ขยาย' (C #)


104

ฉันกำลังพยายามหาวิธีอ่าน / เขียนไปยังคุณสมบัติไฟล์เพิ่มเติมใน C # เช่น Comment, Bit Rate, Date Accessed, Category ฯลฯ ที่คุณเห็นใน Windows explorer มีความคิดอย่างไรในการทำสิ่งนี้? แก้ไข: ฉันจะอ่าน / เขียนไฟล์วิดีโอเป็นหลัก (AVI / DIVX / ... )


3
คำถามนี้เป็นคำถามอย่างชัดเจนไม่ตอบเนื่องจากคำตอบที่ได้รับการยอมรับที่แสดงให้เห็นเพียง แต่วิธีการที่จะได้รับคุณสมบัติที่ขยายและไม่ใช่วิธีการที่จะตั้งพวกเขา
Dmitri Nesteruk

1
สำหรับการตั้งค่าคุณสมบัติเพิ่มเติมโปรดดูที่stackoverflow.com/questions/5337683/…
VoteCoffee

คำตอบ:


83

สำหรับผู้ที่ไม่คลั่งไคล้ 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)}");
        }
    }
}

3
เราจะกำหนดค่าเหล่านี้ได้อย่างไร เช่นผู้แต่งหรือผู้เผยแพร่ไฟล์. txt ฉันใช้ win 7 และใช้สิ่งนี้และแสดงผู้เขียนและผู้จัดพิมพ์เปล่าและคุณสมบัติอื่น ๆ อีก 282 รายการ
Vaibhav Garg

1
@Vainbhav - คุณไม่สามารถตั้งค่าเหล่านี้ได้
csharptest.net

26
คุณต้องเพิ่มข้อมูลอ้างอิงไปยัง Microsoft Shell Controls and Automation จากแท็บ COM ของกล่องโต้ตอบ Refences
csharptest.net

2
วิธีการตั้งค่าจะครอบคลุมในคำถามนี้ดีกว่า: stackoverflow.com/questions/5337683/…
Nicolas Raoul

1
ใน Windows 10 จะส่งกลับเฉพาะ 52 ฟิลด์ไม่รวมอัตราเฟรม, ความสูงของเฟรม, ความกว้าง, .... ?
Minh Nguyen

27

มีบทความ CodeProjectสำหรับผู้อ่าน ID3 และเธรดที่ kixtart.orgที่มีข้อมูลเพิ่มเติมสำหรับคุณสมบัติอื่น ๆ โดยทั่วไปคุณต้องเรียกใช้GetDetailsOf()เมธอดบนโฟลเดอร์เชลล์วัตถุสำหรับshell32.dll.


ขอบคุณฉันน่าจะดึงสิ่งที่ต้องการจากสิ่งนี้มารวมกันได้
David Hayes

27

โซลูชัน 2016

เพิ่มแพ็คเกจ NuGet ต่อไปนี้ในโครงการของคุณ:

  • Microsoft.WindowsAPICodePack-Shell โดย Microsoft
  • Microsoft.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: การใช้ตัวจัดการทรัพย์สิน


ฉันไม่เห็นแพ็คเกจตามชื่อเหล่านี้จาก Microsoft
Jacob Brewer

1
@JacobBrewer มันเป็นจริงหนึ่งที่ถูกอัปโหลดโดย "acdvorak": nuget.org/packages/Microsoft.WindowsAPICodePack-Shell ใน Visual Studio NuGet-Package-Manager จะแสดงเป็น "โดย Microsoft" แพคเกจอื่น ๆ ที่มีชื่อคล้ายกันเป็นของมันและอาจทำงานได้อย่างถูกต้องหรือดีกว่า ฉันไม่รู้ ...
Martin Schneider

25

ตัวอย่างนี้ใน 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ของกล่องโต้ตอบการอ้างอิง


2
ที่น่าสังเกตว่าใน Windows 7 (อย่างน้อย) คุณสามารถเพิ่มขนาดของ arrHeaders เป็นมากกว่า 280 และรับข้อมูลเมตาเพิ่มเติมกลับคืนมาได้มากมาย ฉันพบสิ่งนี้เมื่อฉันกำลังมองหาวิธีรับข้อมูลเมตาจากไฟล์ WTV (Windows 7 Media Center บันทึกรายการโทรทัศน์)
Richard

1
ครั้งแรกสำหรับ i = 0 ถึง 34 loop ควรเป็น i = 0 ถึง Integer.MaxValue จากนั้นทดสอบค่าส่งคืนของ objFolder.GetDetailsOf (objFolderItems, i) หากส่งคืนค่าว่างหรือเว้นวรรคแสดงว่าคุณมีส่วนหัวทั้งหมด
Tim Murphy

@TimMurphy น่าเสียดายที่ไม่ถูกต้อง (อย่างน้อยใน Windows 10 หรือ 7) ส่วนหัวบางส่วนว่างเปล่าดังนั้นคุณต้องวนซ้ำดัชนีทั้งหมด (แน่นอนเนื่องจากมีจำนวนไม่มากคุณสามารถ จำกัด ลูปไว้ที่ 1,000 ได้)
skst

8

ขอบคุณสำหรับกระทู้นี้! มันช่วยฉันเมื่อฉันต้องการหาเวอร์ชันไฟล์ของ exe อย่างไรก็ตามฉันต้องการหาบิตสุดท้ายของสิ่งที่เรียกว่า Extended Properties

หากคุณเปิดคุณสมบัติของไฟล์ exe (หรือ dll) ใน Windows Explorer คุณจะได้รับแท็บเวอร์ชันและมุมมองของ Extended Properties ของไฟล์นั้น ฉันต้องการเข้าถึงหนึ่งในค่าเหล่านั้น

วิธีแก้ปัญหานี้คือตัวทำดัชนีคุณสมบัติ FolderItem.ExtendedProperty และหากคุณวางช่องว่างทั้งหมดในชื่อคุณสมบัติคุณจะได้รับค่า เช่น File Version ไปที่ FileVersion และคุณก็มี

หวังว่านี่จะช่วยคนอื่นคิดว่าฉันจะเพิ่มข้อมูลนี้ในชุดข้อความนี้ ไชโย!


2
นอกจากนี้ยังช่วยให้มั่นใจได้ว่าโค้ดของคุณ (อย่างน้อยส่วนใหญ่) จะยังคงทำงานบนเครื่องที่ไม่ใช่ภาษาอังกฤษ
Ed Norris

1
การปรับปรุงเล็กน้อยที่นี่ FolderItem ไม่มี ExtendedProperty () FolderItem2 อย่างไรก็ตาม
Mixxiphoid

คำตอบนี้ง่ายกว่าข้ออื่น ๆ ฉันให้รหัสตัวอย่างที่ใช้งานได้ที่นี่: stackoverflow.com/a/46648086/661933
nawfal

8

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

ฉันได้คัดลอกและใช้รหัสเดียวกันด้านบน แต่ฉันได้รับข้อยกเว้น COM ที่ runime Folder rFolder = shell.NameSpace(_rootPath);ที่นี่ FYI ฉันใช้ Windows 8 OS
DonMax

1
ข้อผิดพลาดนั้นคืออะไร? ตรวจสอบว่าคุณใช้ Shell32.dll รุ่นที่ถูกต้อง ตรวจสอบสิ่งนี้อาจมีประโยชน์
RajeshKdev

1
+1 สำหรับลิงค์ด้านบน ลิงก์ที่คุณแนะนำใช้งานได้ดี ฉันต้องการอีกหนึ่งความช่วยเหลือจากคุณ เช่นฉันจะส่งไฟล์เดียวเพื่อรับข้อมูลเมตาได้อย่างไร? เนื่องจากยอมรับการส่งผ่านโฟลเดอร์เท่านั้น
DonMax

6
  • หลังจากดูวิธีแก้ปัญหาหลายอย่างในเธรดนี้และที่อื่น ๆ แล้วก็มีการรวบรวมโค้ดต่อไปนี้ นี่เป็นเพียงการอ่านคุณสมบัติเท่านั้น
  • ฉันไม่สามารถรับฟังก์ชัน Shell32.FolderItem2.ExtendedProperty ให้ใช้งานได้มันควรจะรับค่าสตริงและส่งคืนค่าที่ถูกต้องและพิมพ์สำหรับคุณสมบัตินั้น ... นี่เป็นค่าว่างสำหรับฉันเสมอและทรัพยากรอ้างอิงของนักพัฒนาก็บางมาก
  • WindowsApiCodePackดูเหมือนว่าจะได้รับการยกเลิกโดยไมโครซอฟท์ซึ่งจะทำให้เรารหัสข้างล่างนี้

ใช้:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. จะส่งคืนค่าของคุณสมบัติเพิ่มเติมที่คุณต้องการเป็นสตริงสำหรับไฟล์และชื่อคุณสมบัติที่กำหนด
  2. วนซ้ำจนกว่าจะพบคุณสมบัติที่ระบุ - ไม่ใช่จนกว่าคุณสมบัติทั้งหมดจะถูกค้นพบเหมือนโค้ดตัวอย่าง
  3. จะทำงานบน Windows เวอร์ชันเช่น Windows Server 2008 ซึ่งคุณจะได้รับข้อผิดพลาด"Unable to cast COM object of type 'System .__ ComObject' to interface type 'Shell32.Shell'"หากเพียงแค่พยายามสร้าง Shell32 Object ตามปกติ

    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
โปรดทราบว่าแทนที่จะใช้InvokeMember ()คุณสามารถส่งshellไปยังIShellDispatchอินเทอร์เฟซใดก็ได้(1-6) และโทรหาสมาชิกโดยตรง Shell32.IShellDispatch ishell = (Shell32.IShellDispatch)shell; Shell32.Folder shellFolder = ishell.NameSpace(baseFolder);
skst

5

คำตอบของ 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.
}

1

ฉันไม่แน่ใจว่าไฟล์ประเภทใดที่คุณพยายามเขียนคุณสมบัติ แต่taglib-sharpเป็นไลบรารีการติดแท็กโอเพ่นซอร์สที่ยอดเยี่ยมซึ่งรวมฟังก์ชันทั้งหมดนี้ไว้อย่างดี มีการสนับสนุนในตัวสำหรับประเภทไฟล์สื่อยอดนิยมส่วนใหญ่ แต่ยังช่วยให้คุณสามารถทำการแท็กขั้นสูงกับไฟล์ใดก็ได้

แก้ไข: ฉันได้อัปเดตลิงก์ไปยัง taglib sharp แล้ว ลิงก์เก่าใช้งานไม่ได้อีกต่อไป

แก้ไข:อัปเดตลิงก์อีกครั้งตามความคิดเห็นของ kzu


สิ่งนี้ดูน่าสนใจมากฉันจะดูไฟล์วิดีโอเป็นหลัก (AVI, DIVX และอื่น ๆ ) ขอบคุณสำหรับตัวชี้
David Hayes

ลิงค์ taglib-sharp ดูเหมือนจะตาย :-( - ซึ่งแปลกเหมือนวิกิที่ ... developer.novell.com/wiki/index.php/TagLib_Sharp:_Examples ... ชี้ไปที่ URL นั้น
SteveC

ขอบคุณ SteveC ในเวลาที่ฉันโพสต์ลิงก์ทั้งสองนี้ถูกต้องและฉันไม่แน่ใจว่าที่ใดเป็นสถานที่อย่างเป็นทางการดูเหมือนว่าโนเวลล์จะเป็นไซต์ที่เหมาะสมที่จะไปที่ lib นี้ในตอนนี้
จำลอง

ขอบคุณสำหรับการแจ้งเตือน kzu ฉันได้อัปเดตลิงก์ในคำตอบเดิมของฉันเพื่อชี้ไปที่ตำแหน่ง github ด้วย
จำลอง

1

นี่คือวิธีแก้ปัญหาสำหรับการอ่าน - ไม่เขียน - คุณสมบัติเพิ่มเติมตามสิ่งที่ฉันพบในหน้านี้และด้วยความช่วยเหลือเกี่ยวกับวัตถุ 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 เพื่อรับคุณสมบัติการขยายไฟล์

ฉันไม่รู้ว่าชื่อคุณสมบัติเหล่านั้นจะเป็นอย่างไรในระบบต่างประเทศและไม่พบข้อมูลเกี่ยวกับค่าคงที่ที่แปลได้ว่าจะใช้เพื่อเข้าถึงพจนานุกรม ฉันยังพบว่าคุณสมบัติบางอย่างจากกล่องโต้ตอบคุณสมบัติไม่ปรากฏในพจนานุกรมที่ส่งคืน

BTW สิ่งนี้ช้ามากและอย่างน้อยใน Windows 10 การแยกวิเคราะห์วันที่ในสตริงที่ดึงมาจะเป็นเรื่องที่ท้าทายดังนั้นการใช้สิ่งนี้ดูเหมือนจะเป็นความคิดที่ไม่ดีในการเริ่มต้น

ใน Windows 10 คุณควรใช้ไลบรารี Windows.Storage ซึ่งมี SystemPhotoProperties, SystemMusicProperties เป็นต้น https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

และในที่สุดฉันก็โพสต์วิธีแก้ปัญหาที่ดีกว่ามากซึ่งใช้ WindowsAPICodePack ที่นั่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.