Đọc / Ghi thuộc tính tệp 'Mở rộng' (C #)


104

Tôi đang cố gắng tìm cách đọc / ghi vào các thuộc tính tệp mở rộng trong C #, ví dụ: Nhận xét, Tốc độ bit, Ngày truy cập, Danh mục, v.v. mà bạn có thể thấy trong Windows explorer. Bất kỳ ý tưởng làm thế nào để làm điều này? CHỈNH SỬA: Tôi sẽ chủ yếu đọc / ghi vào các tệp video (AVI / DIVX / ...)


3
Câu hỏi này rõ ràng không được trả lời vì câu trả lời được chấp nhận chỉ cho thấy cách lấy các thuộc tính mở rộng chứ không phải cách thiết lập chúng .
Dmitri Nesteruk

1
Để thiết lập các thuộc tính mở rộng, hãy xem stackoverflow.com/questions/5337683/…
VoteCoffee

Câu trả lời:


83

Đối với những người không cuồng VB, đây là trong c #:

Lưu ý, bạn phải thêm tham chiếu đến Microsoft Shell Controls and Automation từ tab COM của hộp thoại Tham chiếu.

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
làm thế nào để đặt một trong những giá trị này? ví dụ: Tác giả hoặc nhà xuất bản cho tệp .txt. Tôi đang trên win 7 và sử dụng này và nó cho thấy một tác giả và nhà xuất bản trống và 282 tài sản khác
Vaibhav Garg

1
@Vainbhav - Bạn không thể đặt chúng.
csharptest.net

26
Bạn phải thêm một tham chiếu đến Microsoft Shell Controls and Automation từ tab COM của hộp thoại Refences.
csharptest.net

2
Cách ĐẶT chúng tốt hơn sẽ được đề cập trong câu hỏi này: stackoverflow.com/questions/5337683/…
Nicolas Raoul

1
Trong Windows 10 nó chỉ trả về 52 trường không bao gồm Frame rate, Frame Height, Width, ....?
Minh Nguyen


26

Giải pháp 2016

Thêm các gói NuGet sau vào dự án của bạn:

  • Microsoft.WindowsAPICodePack-Shell bởi Microsoft
  • Microsoft.WindowsAPICodePack-Core bởi Microsoft

Thuộc tính đọc và ghi

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

Quan trọng:

Tệp phải là tệp hợp lệ, được tạo bởi phần mềm được chỉ định cụ thể. Mọi loại tệp đều có các thuộc tính tệp mở rộng cụ thể và không phải tất cả chúng đều có thể ghi được.

Nếu bạn nhấp chuột phải vào tệp trên màn hình và không thể chỉnh sửa thuộc tính, bạn cũng sẽ không thể chỉnh sửa nó bằng mã.

Thí dụ:

  • Tạo tệp txt trên máy tính để bàn, đổi tên phần mở rộng của nó thành docx. Bạn không thể chỉnh sửa nó Authorhoặc thuộc Titletính.
  • Mở nó bằng Word, chỉnh sửa và lưu nó. Bây giờ bạn có thể.

Vì vậy, chỉ cần đảm bảo sử dụng một số try catch

Chủ đề khác: MSDN: Thực hiện xử lý tài sản


Tôi không thấy bất kỳ gói nào có tên này từ Microsoft
Jacob Brewer

1
@JacobBrewer Nó thực sự là cái được tải lên bởi "acdvorak": nuget.org/packages/Microsoft.WindowsAPICodePack-Shell . Trong Visual Studio NuGet-Package-Manager, nó được hiển thị là "của Microsoft". Các gói khác có tên tương tự là nhánh của nó và cũng có thể hoạt động bình thường hoặc thậm chí tốt hơn. Tôi không biết ...
Martin Schneider

25

Mẫu này trong VB.NET đọc tất cả các thuộc tính mở rộng:

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

Bạn phải thêm tham chiếu đến Microsoft Shell Controls and Automation từ tab COM của hộp thoại Tham chiếu .


2
Cần lưu ý rằng trên Windows 7 (ít nhất), bạn có thể tăng kích thước của arrHeaders lên chỉ hơn 280 và lấy lại nhiều siêu dữ liệu bổ sung. Tôi phát hiện ra điều này khi tôi đang tìm cách lấy siêu dữ liệu từ tệp WTV (Windows 7 Media Center đã ghi lại chương trình truyền hình).
Richard

1
Vòng lặp đầu tiên cho i = 0 đến 34 phải dành cho i = 0 đến Integer.MaxValue. Sau đó kiểm tra giá trị trả về của objFolder.GetDetailsOf (objFolder.Items, i). Nếu nó trả về không gian trống hoặc khoảng trắng thì bạn có tất cả các tiêu đề.
Tim Murphy

@TimMurphy, thật không may, điều đó không chính xác (ít nhất là trên Windows 10 hoặc 7). Một số tiêu đề trống, vì vậy bạn cần lặp qua tất cả các chỉ mục. (Tất nhiên, vì không có hàng triệu người trong số họ, bạn có thể giới hạn vòng lặp ở mức 1.000.)
skst

8

Cảm ơn các bạn cho chủ đề này! Nó đã giúp tôi khi tôi muốn tìm ra phiên bản tệp exe. Tuy nhiên, tôi cần phải tự mình tìm ra chút cuối cùng của cái được gọi là Thuộc tính mở rộng.

Nếu bạn mở thuộc tính của tệp exe (hoặc dll) trong Windows Explorer, bạn sẽ nhận được tab Phiên bản và dạng xem Thuộc tính mở rộng của tệp đó. Tôi muốn truy cập một trong những giá trị đó.

Giải pháp cho điều này là FolderItem.ExtendedProperty của trình lập chỉ mục thuộc tính và nếu bạn bỏ tất cả các khoảng trắng trong tên của thuộc tính, bạn sẽ nhận được giá trị. Ví dụ: Phiên bản tệp chuyển sang FileVersion, và bạn có nó.

Hy vọng điều này sẽ giúp bất kỳ ai khác, chỉ nghĩ rằng tôi muốn thêm thông tin này vào chủ đề này. Chúc mừng!


2
Điều này cũng đảm bảo rằng mã của bạn (ít nhất là hầu hết) vẫn hoạt động trên các máy không sử dụng tiếng Anh.
Ed Norris

1
Một cải tiến nhỏ ở đây, FolderItem không chứa ExtendedProperty (). FolderItem2 thì không.
Mixxiphoid,

Câu trả lời này đơn giản hơn những câu khác. Tôi đã đưa ra mẫu mã mà làm việc ở đây: stackoverflow.com/a/46648086/661933
nawfal

8

GetDetailsOf()Phương pháp - Truy xuất thông tin chi tiết về một mục trong một thư mục. Ví dụ: kích thước, loại hoặc thời gian sửa đổi lần cuối. Thuộc tính Tệp có thể thay đổi tùy theo Windows-OSphiên bản.

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

Tôi đã sao chép và sử dụng cùng một đoạn mã ở trên. Nhưng, tôi nhận được ngoại lệ COM tại runime đây Folder rFolder = shell.NameSpace(_rootPath);. FYI, tôi đang sử dụng HĐH Windows 8.
DonMax

1
Đó là lỗi gì? Đảm bảo rằng bạn đang sử dụng đúng phiên bản Shell32.dll. Kiểm tra này nó có thể hữu ích
RajeshKdev

1
+1 cho liên kết trên. Liên kết mà bạn đề xuất đang hoạt động tốt. Tôi cần thêm một sự giúp đỡ từ bạn. tức là, Làm cách nào tôi có thể chuyển một tệp để lấy siêu dữ liệu ?? kể từ đó, nó chỉ chấp nhận chuyển thư mục.
DonMax

6
  • Sau khi xem xét một số giải pháp trên chủ đề này và các nơi khác, mã sau đây đã được ghép lại với nhau. Đây chỉ để đọc một tài sản.
  • Tôi không thể làm cho hàm Shell32.FolderItem2.ExtendedProperty hoạt động, nó phải nhận một giá trị chuỗi và trả về giá trị và kiểu chính xác cho thuộc tính đó ... điều này luôn là null đối với tôi và tài nguyên tham chiếu của nhà phát triển rất mỏng.
  • Các WindowsApiCodePack dường như đã bị bỏ rơi bởi Microsoft mà đưa chúng ta vào mã bên dưới.

Sử dụng:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Sẽ trả lại cho bạn giá trị của thuộc tính mở rộng mà bạn muốn dưới dạng một chuỗi cho tên thuộc tính và tệp đã cho.
  2. Chỉ lặp lại cho đến khi nó tìm thấy thuộc tính được chỉ định - không phải cho đến khi tất cả các thuộc tính được phát hiện như một số mã mẫu
  3. Sẽ hoạt động trên các phiên bản Windows như Windows server 2008, nơi bạn sẽ gặp lỗi "Không thể truyền đối tượng COM thuộc loại 'Hệ thống .__ ComObject' sang loại giao diện 'Shell32.Shell'" nếu chỉ cố tạo Đối tượng Shell32 bình thường.

    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
Lưu ý rằng thay vì sử dụng InvokeMember () , bạn có thể truyền shelltới bất kỳ IShellDispatchgiao diện nào (1-6) và gọi trực tiếp thành viên. Shell32.IShellDispatch ishell = (Shell32.IShellDispatch)shell; Shell32.Folder shellFolder = ishell.NameSpace(baseFolder);
skst

5

Câu trả lời của Jerker đơn giản hơn một chút. Đây là mã mẫu hoạt động từ MS :

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

Đối với những người không thể tham chiếu tĩnh shell32, bạn có thể gọi nó động như sau:

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

Tôi không chắc bạn đang cố gắng viết các thuộc tính cho loại tệp nào nhưng taglib-sharp là một thư viện gắn thẻ mã nguồn mở tuyệt vời gói gọn tất cả chức năng này một cách độc đáo. Nó hỗ trợ rất nhiều cho hầu hết các loại tệp phương tiện phổ biến nhưng cũng cho phép bạn thực hiện gắn thẻ nâng cao hơn với khá nhiều tệp bất kỳ.

CHỈNH SỬA: Tôi đã cập nhật liên kết đến taglib sắc nét. Liên kết cũ không còn hoạt động.

EDIT: Đã cập nhật liên kết một lần nữa theo nhận xét của kzu.


Điều này trông rất thú vị, tôi sẽ chủ yếu xem các tệp video (AVI, DIVX, v.v.). Cảm ơn vì con trỏ
David Hayes

Liên kết taglib-sharp có vẻ đã chết :-( - thật kỳ lạ như wiki tại ... developer.novell.com/wiki/index.php/TagLib_Sharp:_Examples ... trỏ đến URL đó
SteveC

Cảm ơn, SteveC, tại thời điểm tôi đăng bài này, cả hai liên kết đều hợp lệ và tôi không chắc đâu là nơi chính thức để đến, có vẻ như novell là trang web phù hợp để truy cập vào lib này ngay bây giờ.
mockobject

Cảm ơn các bạn đã biết, tôi đã cập nhật liên kết trong câu trả lời ban đầu của mình để trỏ đến vị trí github.
mockobject

1

Đây là một giải pháp để đọc - không phải ghi - các thuộc tính mở rộng dựa trên những gì tôi tìm thấy trên trang này và trợ giúp với các đối tượng shell32 .

Để rõ ràng đây là một vụ hack. Có vẻ như mã này sẽ vẫn chạy trên Windows 10 nhưng sẽ hiển thị trên một số thuộc tính trống. Phiên bản trước của Windows nên sử dụng:

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

Trên Windows 10, chúng tôi giả định rằng có khoảng 320 thuộc tính để đọc và chỉ cần bỏ qua các mục trống:

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

Như đã đề cập, bạn cần tham khảo Com assembly Interop.Shell32.

Nếu bạn nhận được một ngoại lệ liên quan đến STA, bạn sẽ tìm thấy giải pháp ở đây:

Ngoại lệ khi sử dụng Shell32 để nhận thuộc tính mở rộng Tệp

Tôi không biết những tên thuộc tính đó sẽ như thế nào trên một hệ thống nước ngoài và không thể tìm thấy thông tin về những hằng số có thể bản địa hóa sẽ sử dụng để truy cập từ điển. Tôi cũng thấy rằng không phải tất cả các thuộc tính từ hộp thoại Thuộc tính đều có trong từ điển được trả về.

BTW điều này cực kỳ chậm và - ít nhất là trên Windows 10 - phân tích cú pháp ngày trong chuỗi được truy xuất sẽ là một thách thức vì vậy sử dụng điều này có vẻ là một ý tưởng tồi khi bắt đầu.

Trên Windows 10, bạn chắc chắn nên sử dụng thư viện Windows.Storage chứa SystemPhotoProperties, SystemMusicProperties, v.v. https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

Và cuối cùng, tôi đã đăng một giải pháp tốt hơn nhiều sử dụng WindowsAPICodePack ở đó

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.