在这里和其他地方阅读各种答案,我将这一部分拼凑在一起以获得我需要的文件元数据:
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
它不是世界上最高效的代码,即获取目录中每个文件的 path 属性来标识我真正感兴趣的文件。优化它以仅读取每个文件的 path 属性一次,使其速度提高约 50%(通过让它获取它找到的第一个文件来测试它是否是正确的文件(,但无论如何,它比预期的要慢得多。
它需要从每个文件中获取 24 个属性,并且需要从 ~100k 内查找大约 20k 个文件,目前这需要整整一个小时。
分析告诉我,CPU是瓶颈,任何占用周期的东西我都看不到,因为它在Shell32.Folder.GetDetailsOf方法中占99%。
有没有更快的方法来获取元数据?答案不必特定于 vb 或 .net。
由于您正在寻求最大速度,因此建议您为代码启用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.ParseName 方法直接检索FolderItem
对象,而不是枚举Shell32.Folder.Items
集合。 此对象可以强制转换为允许使用 ShellFolderItem.ExtendedProperty 方法的Shell32.ShellFolderItem
。
有两种方法可以指定属性。首先是分配 属性的知名名称,例如"作者"或"日期",到 sPropName。 但是,每个属性都是组件对象模型 (COM( 的成员 属性集,也可以通过指定其格式 ID 来标识 (FMTID( 和属性 ID (PID(。FMTID 是标识 属性集,PID 是标识特定 属性集中的属性。
通过其 FMTID/PID 值指定属性通常更多 比使用其名称更有效。使用属性的 FMTID/PID 值 使用扩展属性,它们必须组合成一个 SCID。SCID 是 一个字符串,包含 "FMTID**PID" 形式的 FMTID/PID 值, 其中,FMTID 是属性集的 GUID 的字符串形式。为 例如,摘要信息属性集作者的 SCID 属性为"{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 4"。
许多 FMTID/PID 值可以在 Windows Properties.
上提供的链接下找到,您可以在此处找到完整的属性表(向下滚动(。
将一些选定属性放在一起:
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
更快,但其他更改应该会有所改进。