Существует ли более быстрый способ получения метаданных файла, чем при использовании компонента COM оболочки? - PullRequest
0 голосов
/ 01 июля 2018

Читая различные ответы здесь и в других местах, я собрал этот бит, чтобы получить метаданные файла, которые мне нужны:

Public Class windows_metadata_helper
    Public Shared shell As New Shell32.Shell
    Public Shared indices_of_interest As New Dictionary(Of Integer, String)
    Public Shared path_index As Integer

    Shared Sub New()
        'snipped long piece code for figuring out the indices of the attributes that I need, they are stored in indices_of_interest, for example 0:Name
    End Sub

    Public Shared Function get_interesting_data(path) As Dictionary(Of String, String)
        Dim fi As New IO.FileInfo(path)
        Dim f_dir = shell.NameSpace(fi.DirectoryName)
        Dim data As New Dictionary(Of String, String)

        For Each item In f_dir.Items()
            If f_dir.GetDetailsOf(item, path_index) = fi.FullName Then
                For Each kvp In indices_of_interest
                    Dim val = f_dir.GetDetailsOf(item, kvp.Key)
                    If Not String.IsNullOrEmpty(val) Then data.Add(kvp.Value, val)
                Next
                Exit For
            End If
        Next

        Return data
    End Function
End Class

Это не самый эффективный код в мире, а именно получение атрибута пути каждого файла в каталоге, чтобы идентифицировать файл, который мне действительно интересен. Оптимизация позволяет только читать атрибут пути каждого файла, как только он обходит его. На 50% быстрее (тестируется, позволяя ему взять первый файл, который он находит, является ли он правильным или нет), но независимо от этого, он намного медленнее, чем ожидалось.

Необходимо извлечь 24 атрибута из каждого файла и найти около 20 тыс. Файлов из ~ 100 тыс., В настоящее время это занимает целый час.

Профилирование говорит мне, что ЦП является узким местом, и что бы ни занимало циклы, которые я не вижу, поскольку его 99% внутри метода Shell32.Folder.GetDetailsOf.

Есть ли более быстрый способ получения метаданных? Ответ не должен быть специфичным для vb или .net.

1 Ответ

0 голосов
/ 03 июля 2018

Поскольку вы ищете максимальную скорость, я предлагаю включить Option Strict для своего кода и внести необходимые изменения, которые будут предложены в среде IDE. Это исключит ненужные преобразования типов.

Например,

Public Shared Function get_interesting_data(path) As Dictionary(Of String, String)

должно быть:

Public Shared Function get_interesting_data(path As String) As Dictionary(Of String, String)

Вместо перечисления коллекции Shell32.Folder.Items используйте метод *1011* Shell32.Folder.ParseName для непосредственного получения FolderItem объекта. Этот объект может быть приведен к Shell32.ShellFolderItem, что позволит использовать метод ShellFolderItem.ExtendedProperty .

Есть два способа указать свойство. Во-первых, назначить известное имя свойства, например «Автор» или «Дата», для sPropName. Однако каждое свойство является членом объектной модели компонентов (COM) набор свойств и также может быть идентифицирован путем указания его идентификатора формата (FMTID) и идентификатор недвижимости (PID). FMTID - это GUID, который идентифицирует набор свойств, а PID - это целое число, которое идентифицирует конкретный свойство в наборе свойств.

Задание свойства по значениям FMTID / PID обычно больше эффективнее, чем используя его имя . Чтобы использовать значения FMTID / PID свойства с ExtendedProperty они должны быть объединены в SCID. SCID это строка, содержащая значения FMTID / PID в форме «FMTID ** PID», где FMTID - это строковая форма GUID набора свойств. За Например, SCID автора набора свойств сводной информации свойство "{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 4".

Значения FMTID / PID можно найти по ссылкам, представленным в Свойства Windows .

Соедините это для некоторых выбранных свойств:

Public Shared Function get_interesting_data(path As String) As Dictionary(Of String, String)
    Dim fi As New IO.FileInfo(path)
    Dim f_dir As Shell32.Folder = shell.NameSpace(fi.DirectoryName)

    ' instead of enumerating f_dir.Items to find the file of interest
    ' directly retrieve the item reference
    Dim item As Shell32.ShellFolderItem = DirectCast(f_dir.ParseName(fi.Name), Shell32.ShellFolderItem)

    Dim scid_Bitrate As String = "{64440490-4C8B-11D1-8B70-080036B11A03} 4"    ' Audio: System.Audio.EncodingBitrate
    Dim scid_Title As String = "{F29F85E0 - 4.0FF9-1068-AB91-08002B27B3D9} 2"  ' Core: System.Title
    Dim scid_Created As String = "{B725F130-47EF-101A-A5F1-02608C9EEBAC} 15"   ' Core: System.DateCreated
    Dim scid_Copyright As String = "{64440492-4C8B-11D1-8B70-080036B11A03} 11" ' Core: System.Copyright
    Dim scid_Publisher As String = "{64440492-4C8B-11D1-8B70-080036B11A03} 30" ' Media: System.Media.Publisher
    Dim scid_FullDetails As String = "{C9944A21-A406-48FE-8225-AEC7E24C211B} 2" ' PropList: System.PropList.FullDetails

    Dim bitrate As Object = item.ExtendedProperty(scid_Bitrate)
    Dim title As Object = item.ExtendedProperty(scid_Title)
    Dim created As Object = item.ExtendedProperty(scid_Created)
    Dim copyright As Object = item.ExtendedProperty(scid_Copyright)
    Dim publisher As Object = item.ExtendedProperty(scid_Publisher)
    Dim fullDetails As Object = item.ExtendedProperty(scid_FullDetails)

    Dim data As New Dictionary(Of String, String)
    ' save the retrieved properties

    Return data
End Function

Я не знаю, быстрее ли этот метод извлечения свойств, чем вы используете GetDetailsOf, но другие изменения должны внести некоторые улучшения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...