我决定编写自己的答案,以尝试结合和澄清上述答案(这极大地帮助了我解决了我的问题)。
我想说有两种方法可以解决这个问题。
情况1:您知道文件包含哪些元数据(您对哪些元数据感兴趣)。
在这种情况下,假设您有一个字符串列表,其中包含您感兴趣的元数据。我在这里假设这些标签是正确的(即您对 .txt 文件的像素数不感兴趣)。
metadata = ['Name', 'Size', 'Item type', 'Date modified', 'Date created']
现在,使用 Greedo 和 Roger Upole 提供的代码,我创建了一个函数,该函数分别接受文件的完整路径和名称,并返回包含感兴趣的元数据的字典:
def get_file_metadata(path, filename, metadata):
# Path shouldn't end with backslash, i.e. "E:\Images\Paris"
# filename must include extension, i.e. "PID manual.pdf"
# Returns dictionary containing all file metadata.
sh = win32com.client.gencache.EnsureDispatch('Shell.Application', 0)
ns = sh.NameSpace(path)
# Enumeration is necessary because ns.GetDetailsOf only accepts an integer as 2nd argument
file_metadata = dict()
item = ns.ParseName(str(filename))
for ind, attribute in enumerate(metadata):
attr_value = ns.GetDetailsOf(item, ind)
if attr_value:
file_metadata[attribute] = attr_value
return file_metadata
# *Note: you must know the total path to the file.*
# Example usage:
if __name__ == '__main__':
folder = 'E:\Docs\BMW'
filename = 'BMW series 1 owners manual.pdf'
metadata = ['Name', 'Size', 'Item type', 'Date modified', 'Date created']
print(get_file_metadata(folder, filename, metadata))
结果:
{'Name': 'BMW series 1 owners manual.pdf', 'Size': '11.4 MB', 'Item type': 'Foxit Reader PDF Document', 'Date modified': '8/30/2020 11:10 PM', 'Date created': '8/30/2020 11:10 PM'}
这是正确的,因为我刚刚创建了文件,并且我使用 Foxit PDF 阅读器作为我的主要 pdf 阅读器。所以这个函数返回一个字典,其中键是元数据标签,值是给定文件的这些标签的值。
情况 2:您不知道文件包含哪些元数据
这是一个更艰难的情况,尤其是在最优性方面。我分析了 Roger Upole 提出的代码,基本上,他试图读取None
文件的元数据,这导致他获得了所有可能的元数据标签的列表。所以我认为硬拷贝这个列表然后尝试读取每个标签可能更容易。这样,一旦完成,您将拥有一个包含文件实际拥有的所有标签的字典。
只需复制我认为所有可能的元数据标签,然后尝试从文件中获取所有标签。基本上,只需复制这个 python 列表的声明,并使用上面的代码(用这个新列表替换元数据):
metadata = ['Name', 'Size', 'Item type', 'Date modified', 'Date created', 'Date accessed', 'Attributes', 'Offline status', 'Availability', 'Perceived type', 'Owner', 'Kind', 'Date taken', 'Contributing artists', 'Album', 'Year', 'Genre', 'Conductors', 'Tags', 'Rating', 'Authors', 'Title', 'Subject', 'Categories', 'Comments', 'Copyright', '#', 'Length', 'Bit rate', 'Protected', 'Camera model', 'Dimensions', 'Camera maker', 'Company', 'File description', 'Masters keywords', 'Masters keywords']
我不认为这是一个很好的解决方案,但另一方面,您可以将此列表保留为全局变量,然后使用它而无需将其传递给每个函数调用。为了完整起见,这里是使用这个新元数据列表的前一个函数的输出:
{'Name': 'BMW series 1 owners manual.pdf', 'Size': '11.4 MB', 'Item type': 'Foxit Reader PDF Document', 'Date modified': '8/30/2020 11:10 PM', 'Date created': '8/30/2020 11:10 PM', 'Date accessed': '8/30/2020 11:10 PM', 'Attributes': 'A', 'Perceived type': 'Unspecified', 'Owner': 'KEMALS-ASPIRE-E\\kemal', 'Kind': 'Document', 'Rating': 'Unrated'}
如您所见,返回的字典现在包含文件包含的所有元数据。之所以有效,是因为if 语句:
if attribute_value:
这意味着只要一个属性等于None
,它就不会被添加到返回的字典中。
我要强调的是,在处理许多文件的情况下,最好将列表声明为全局/静态变量,而不是每次都将其传递给函数。