【问题标题】:Cross platform hidden file detection跨平台隐藏文件检测
【发布时间】:2010-09-21 23:56:34
【问题描述】:

跨平台处理隐藏文件的最佳方法是什么? (最好在 Python 中,但仍然赞赏其他解决方案)

只需检查前导 '.'适用于 *nix/Mac,文件属性适用于 Windows。但是,这似乎有点简单,并且也没有考虑隐藏事物的替代方法(.hidden 文件等)。有没有标准的方法来处理这个问题?

【问题讨论】:

  • 这个抽象的讨论很棒,但我也想看代码!看看我必须自己用谷歌搜索所有内容。
  • linux中没有隐藏文件的概念,点文件一般是不显示的,但是文件是不能隐藏的。这是一个纯粹的 DOS/Windows 概念 AFAIK。
  • 在OS X中一个隐藏文件的概念。当然你可以在Finder中显示隐藏文件,就像你可以将-a传递给ls一样,但是他们仍然被称为隐藏。前导点也不是隐藏某些东西的唯一方法。如果您需要,请参阅我的答案。
  • 另外,虽然 linux 内核显然没有定义“隐藏文件”的概念,但 freedesktop 和其他标准(或协作或其他)定义了很多内核没有定义的东西。如果您的文件管理器、应用程序的打开/保存对话框等都同意默认隐藏的内容,那么这很重要。从技术上讲,你真的应该谈论“GNU/linux/FSH/freedesktop/blah/blah 上的隐藏文件”而不是“linux”,但是......无论如何,OP 并不是第一个说“linux”的人。
  • @abarnert:macOS 有 两种 种隐藏文件。 -a 将在ls 输出中包含以. 开头的文件。但是可以使用额外的标志从 Finder 中隐藏文件,这些标志不会从ls 输出中隐藏它们。 ls 通常甚至不会显示这些标志,但添加 -O 会显示它们。

标签: python cross-platform filesystems


【解决方案1】:

“有处理这个问题的标准方法吗?”是的。使用标准(即 POSIX 兼容)操作系统。

由于 Windows 是非标准的——好吧——没有适用的标准。如果有的话不是很好吗?我感觉到你的痛苦。

任何你尝试做的跨平台的事情都会有 Win32 的奇怪之处。

您的解决方案——就目前的情况而言——非常好。在未来的某个时候,Microsoft 可能会选择编写符合 POSIX 的操作系统。在那之前,你可以很好地应对这种情况。

【讨论】:

  • @S.Lott:我通常喜欢你的 cmets,但这没有帮助。标准库中还有许多其他模块可以处理 Windows 的非标准方式。我确定 OP 只是在寻找类似的东西。
  • @technomalogical:确实,有些模块可以最大限度地减少差异。关键是非标准意味着非标准。这是一个无赖。没有使非标准操作系统看起来标准的仙尘解决方案。 OP 有一个很好的解决方案。
【解决方案2】:

我们实际上在我们编写的项目中解决了这个问题。我们所做的是在主检查器中注册了许多不同的“隐藏文件检查器”。我们通过这些传递每个文件,看看它是否应该被隐藏。

这些检查器不仅适用于不同的操作系统等,而且我们插入版本控制“忽略”文件,以及通过 glob 或正则表达式可选的用户覆盖。

它主要相当于你所做的,但以一种可插入、灵活和可扩展的方式。

在此处查看源代码:https://bitbucket.org/aafshar/pida-main/src/tip/pida/services/filemanager/filemanager.py

【讨论】:

  • 这个项目是开源的吗?您可以发布此代码的源代码吗?您大致了解它的工作原理,但示例或伪代码会有所帮助。
  • 是的,它是开源的。 pida.co.uk,这里列出了源代码pida.co.uk/trac/browser/pida/services/filemanager。请记住,将内容插入其中的架构在核心应用程序中处于较高位置,代码的任何其他部分都可以“注册”以使用它。
  • 此 URL 已失效(没有此类域),en.wikipedia.org/wiki/PIDA 链接到同一个 URL。由于这是 5 年的历史,这并不奇怪……但是对于人们仍然要求重复的问题有这样一个过时的答案,这有点令人失望。
  • @abarnert 2 年后,我也在寻找答案
【解决方案3】:

这是一个在 Python 2.5+ 上运行的脚本,应该可以满足您的需求:

import ctypes
import os

def is_hidden(filepath):
    name = os.path.basename(os.path.abspath(filepath))
    return name.startswith('.') or has_hidden_attribute(filepath)

def has_hidden_attribute(filepath):
    try:
        attrs = ctypes.windll.kernel32.GetFileAttributesW(unicode(filepath))
        assert attrs != -1
        result = bool(attrs & 2)
    except (AttributeError, AssertionError):
        result = False
    return result

我在jaraco.windows 中添加了类似于 has_hidden_​​attribute 的内容。如果你有 jaraco.windows >= 2.3:

from jaraco.windows import filesystem

def has_hidden_attribute(filepath):
    return filesystem.GetFileAttributes(filepath).hidden

正如 Ben 所指出的,在 Python 3.5 上,您可以使用 stdlib:

import os, stat

def has_hidden_attribute(filepath):
    return bool(os.stat(filepath).st_file_attributes & stat.FILE_ATTRIBUTE_HIDDEN)

尽管您可能仍希望将 jaraco.windows 用于更多 Pythonic API。

【讨论】:

  • 我不得不更正 is_hidden 因为它没有在 Unix 上进行适当的测试。事实上,我什至不清楚在 Unix 上什么是正确的测试。 '..' 是隐藏的吗?关于什么 '../..'?当然特殊名称是隐藏的,但是函数应该解决它吗?为了兼容性,我是这么认为的。我更改了is_hidden 来测试startswith('.') 的基本名称。
  • 这仍然不能处理 OS X 中的 HFS+ 隐藏属性,或者像 ~/Library 在 OS X 10.7+ 中隐藏的特殊规则,或者......
  • 如果文件不存在 is_hidden 返回 False 而不是抛出。可能已经进行了编辑。
  • @ubershmekel os.path is 函数不检查文件是否存在。如果这些是链接的,比如if exists(f) and isfile(f) and islink(f),那么每个调用都会检查文件是否存在。
  • 注意:在 Python 3.5 及更高版本上,Win32 文件属性可直接通过 os.stat(path).st_file_attributes 获得。 See the docs.
【解决方案4】:

Jason R. Coombs 的回答对于 Windows 来说已经足够了。和大多数 POSIX GUI 文件管理器/打开对话框/等。可能遵循与ls 相同的“点前缀表示隐藏”约定。但不是 Mac OS X。

在Finder、文件打开面板等中隐藏文件或目录的方法至少有四种:

  • 点前缀。
  • HFS+ 不可见属性。
  • Finder 信息隐藏标志。
  • 匹配 CoreFoundation 中内置的特殊黑名单(每个操作系统版本都不同,例如,~/Library 在 10.7+ 中隐藏,但在 10.6 中不隐藏)。

尝试编写自己的代码来处理所有这些问题并不容易。而且你必须保持最新,因为我愿意打赌黑名单会随着大多数操作系统版本而改变,Finder Info 最终会从弃用变为完全不受支持,扩展属性可能比 HFS+ 得到更广泛的支持,……

但是如果你可以要求pyobjc(它已经包含在最近的Apple提供的Python中,并且可以通过pip安装),你可以调用Apple的代码:

import Foundation

def is_hidden(path):
    url = Foundation.NSURL.fileURLWithPath_(path)
    return url.getResourceValue_forKey_error_(None, Foundation.NSURLIsHiddenKey, None)[0]

def listdir_skipping_hidden(path):
    url = Foundation.NSURL.fileURLWithPath_(path)
    fm = Foundation.NSFileManager.defaultManager()
    urls = fm.contentsOfDirectoryAtURL_includingPropertiesForKeys_options_error_(
        url, [], Foundation.NSDirectoryEnumerationSkipsHiddenFiles, None)[0]
    return [u.path() for u in urls]

这应该适用于 pyobjc 支持的任何 Python,在 OS X 10.6+ 上。如果您想要 10.5 或更早版本,目录枚举标志尚不存在,因此唯一的选择是在 is_hidden 上过滤 contentsOfDirectoryAtPath_error_(或只是 os.listdir)之类的东西。

如果您必须在没有 pyobjc 的情况下过日子,您可以下拉到 CoreFoundation 等效项,然后使用 ctypes。关键功能是CFURLCopyResourcePropertyForKey 用于is_hiddenCFURLEnumeratorCreateForDirectoryURL 用于列出目录。

请参阅http://pastebin.com/aCUwTumB 了解实现。

我已经测试过:

  • OS X 10.6,32 位 python.org 3.3.0
  • OS X 10.8,32 位 Apple 2.7.2
  • OS X 10.8,64 位 Apple 2.7.2
  • OS X 10.8,64 位 python.org 3.3.0

它适用于每一个(例如,它在 10.8 上跳过 ~/Library,但在 10.6 上显示它)。

应该适用于任何 OS X 10.6+ 和任何 Python 2.6+。如果您需要 OS X 10.5,则需要使用旧 API(或 os.listdir)并过滤 is_hidden。如果您需要 Python 2.5,请将 bytes 检查更改为 str 检查(这当然会破坏 3.x)并将 with 更改为丑陋的 try/finally 或手动释放。

如果有人计划将此代码放入库中,我强烈建议首先检查pyobjcimport Foundation,如果您没有获得ImportError,您就赢了),并且只使用@987654347 @code 如果它不可用。


最后一点:

一些寻找这个答案的人正试图重新发明一个他们不需要的轮子。

通常,当人们在做这样的事情时,他们正在构建一个 GUI,并希望,例如,显示一个文件浏览器,并带有隐藏或显示隐藏文件的选项。许多流行的跨平台 GUI 框架(Qt、wx 等)都内置了这种支持。(而且,其中许多是开源的,因此您可以阅读他们的代码以了解他们是如何做到的。)

这可能无法回答您的问题 - 例如,他们可能只是将“过滤隐藏文件”标志传递给平台的本机文件浏览器对话框,但您正在尝试构建控制台模式文件浏览器并且可以'不要那样做。但如果是的话,就用它吧。

【讨论】:

  • 很好的答案,尽管它显然是特定于 Mac 的。如果您愿意提供仅使用 ctypes 和 CoreFoundation 等效项的实现,我会将其合并到我的通用实现答案中。
  • @JasonR.Coombs:我认为如果可用的话,使用 pyobjc 实际上会更好(同样,它适用于 Apple 提供的 Python)……但是回退到 CF 并不是一个坏主意。让我找到等价物并写下来。
  • 现在我有一台 Mac,我有机会实现和测试这个功能。不幸的是,我发现即使是 pyobjc 实现也不适合我。特别是,getResourceValue_forKey_error_ 的结果的 [0] 始终为 True。查看结果,似乎[1] 是所需的值。我对 Objective-C 和 pyobjc 的不熟悉让我无法解释。
【解决方案5】:

结合我之前的答案以及@abarnert 的答案,我发布了jaraco.path 1.1,它具有对隐藏文件检测的跨平台支持。安装该软件包后,要检测任何文件的隐藏状态,只需调用 is_hidden

from jaraco import path
path.is_hidden(file)

【讨论】:

  • 太好了,不幸的是这个库(目前)依赖于Foundation
  • 我很乐意用基于 ctypes 的实现来更新它,或者如果你能起草一项技术,我会添加对 pyobjc 的要求。
猜你喜欢
  • 2014-10-15
  • 2022-01-14
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 2010-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多