developer tip

'확장'파일 속성 읽기 / 쓰기 (C #)

copycodes 2020. 8. 25. 08:17
반응형

'확장'파일 속성 읽기 / 쓰기 (C #)


Windows 탐색기에서 볼 수있는 C #의 확장 파일 속성 (예 : 설명, 비트 전송률, 액세스 한 날짜, 범주 등)을 읽고 쓰는 방법을 찾으려고합니다. 이 작업을 수행하는 방법에 대한 아이디어가 있습니까? 편집 : 주로 비디오 파일 (AVI / DIVX / ...)을 읽고 쓸 것입니다.


VB에 열광하지 않는 사람들을 위해 여기에 C #이 있습니다.

참조 대화 상자의 COM 탭에서 Microsoft Shell 컨트롤 및 자동화 에 대한 참조를 추가해야합니다 .

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

ID3 리더를위한 CodeProject 기사 가 있습니다 . 다른 속성에 대한 자세한 정보가 있는 kixtart.org스레드 . 기본적으로, 당신은 호출 할 필요는 GetDetailsOf()방법 상의 폴더 에 대한 셸 개체를 shell32.dll.


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

참조 대화 상자 COM에서 Microsoft Shell 컨트롤 및 자동화 에 대한 참조를 추가해야합니다 .


솔루션 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

Further Topic: MSDN: Implementing Property Handlers


Thank you guys for this thread! It helped me when I wanted to figure out an exe's file version. However, I needed to figure out the last bit myself of what is called Extended Properties.

If you open properties of an exe (or dll) file in Windows Explorer, you get a Version tab, and a view of Extended Properties of that file. I wanted to access one of those values.

The solution to this is the property indexer FolderItem.ExtendedProperty and if you drop all spaces in the property's name, you'll get the value. E.g. File Version goes FileVersion, and there you have it.

Hope this helps anyone else, just thought I'd add this info to this thread. Cheers!


GetDetailsOf() Method - Retrieves details about an item in a folder. For example, its size, type, or the time of its last modification. File Properties may vary based on the Windows-OS version.

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

Jerker's answer is little simpler. Here's sample code which works from MS:

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

For those who can't reference shell32 statically, you can invoke it dynamically like this:

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

  • After looking at a number of solutions on this thread and elsewhere the following code was put together. This is only to read a property.
  • I could not get the Shell32.FolderItem2.ExtendedProperty function to work, it is supposed to take a string value and return the correct value and type for that property... this was always null for me and developer reference resources were very thin.
  • The WindowsApiCodePack seems to have been abandoned by Microsoft which brings us the code below.

Use:

string propertyValue = GetExtendedFileProperty("c:\\temp\\FileNameYouWant.ext","PropertyYouWant");
  1. Will return you the value of the extended property you want as a string for the given file and property name.
  2. Only loops until it found the specified property - not until all properties are discovered like some sample code
  3. Will work on Windows versions like Windows server 2008 where you will get the error "Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'" if just trying to create the Shell32 Object normally.

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

I'm not sure what types of files you are trying to write the properties for but taglib-sharp is an excellent open source tagging library that wraps up all this functionality nicely. It has a lot of built in support for most of the popular media file types but also allows you to do more advanced tagging with pretty much any file.

EDIT: I've updated the link to taglib sharp. The old link no longer worked.

EDIT: Updated the link once again per kzu's comment.


Here is a solution for reading - not writing - the extended properties based on what I found on this page and at help with shell32 objects.

To be clear this is a hack. It looks like this code will still run on Windows 10 but will hit on some empty properties. Previous version of Windows should use:

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

On Windows 10 we assume that there are about 320 properties to read and simply skip the empty entries:

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

As mentioned you need to reference the Com assembly Interop.Shell32.

If you get an STA related exception, you will find the solution here:

Exception when using Shell32 to get File extended properties

I have no idea what those properties names would be like on a foreign system and couldn't find information about which localizable constants to use in order to access the dictionary. I also found that not all the properties from the Properties dialog were present in the dictionary returned.

BTW this is terribly slow and - at least on Windows 10 - parsing dates in the string retrieved would be a challenge so using this seems to be a bad idea to start with.

On Windows 10 you should definitely use the Windows.Storage library which contains the SystemPhotoProperties, SystemMusicProperties etc. https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties

And finally, I posted a much better solution that uses WindowsAPICodePack there

참고URL : https://stackoverflow.com/questions/220097/read-write-extended-file-properties-c

반응형