Межплатформенное обнаружение скрытых файлов - PullRequest
15 голосов
/ 12 ноября 2008

Каков наилучший способ межплатформенной обработки скрытых файлов? (желательно на Python, но другие решения все же приветствуются)

Просто проверяю ведущий '.' работает для * nix / Mac, а атрибуты файлов работают в Windows. Однако это кажется немного упрощенным и также не учитывает альтернативные способы сокрытия вещей (скрытые файлы и т. Д.) Есть ли стандартный способ справиться с этим?

Ответы [ 5 ]

19 голосов
/ 16 июня 2011

Вот скрипт, который работает на 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

Я добавил что-то похожее на has_hidden_attribute в jaraco.windows . Если у вас есть jaraco.windows> = 2.3:

from jaraco.windows import filesystem

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

Как отметил Бен, в 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.

9 голосов
/ 06 марта 2013

Ответа Джейсона Р. Кумбса достаточно для Windows. И большинство файловых менеджеров POSIX GUI / открытых диалогов / и т.д. вероятно, следует тому же соглашению "точка-префикс-значит-скрыто", что и ls. Но не Mac OS X.

Существует как минимум четыре способа скрыть файл или каталог в Finder, панелях открытия файлов и т. Д.:

  • Префикс точки.
  • HFS + невидимый атрибут.
  • Флаг поиска информации скрыт.
  • Соответствует специальному черному списку, встроенному в CoreFoundation (который отличается в каждой версии ОС - например, ~/Library скрыт в 10.7+, но не в 10.6).

Попытка написать собственный код для обработки всего этого не будет легкой. И вам придется поддерживать его в актуальном состоянии, так как я готов держать пари, что черный список будет меняться с большинством версий ОС, в итоге Finder Info перейдет от устаревшего к полностью неподдерживаемому, расширенные атрибуты могут поддерживаться более широко, чем HFS + ,…

Но если вам может потребоваться pyobjc (который уже включен в недавний Python от Apple и может быть установлен через 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]

Это должно работать на любом Python, который поддерживает pyobjc, на OS X 10.6+. Если вы хотите 10.5 или более раннюю версию, флаги перечисления каталога еще не существовали, поэтому единственная опция - это что-то вроде фильтрации чего-то вроде contentsOfDirectoryAtPath_error_ (или просто os.listdir) на is_hidden.

Если вам нужно обойтись без pyobjc, вы можете перейти к CoreFoundation эквивалентам и использовать ctypes. Ключевыми функциями являются CFURLCopyResourcePropertyForKey для is_hidden и CFURLEnumeratorCreateForDirectoryURL для отображения каталога.

См. 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

Он работает соответствующим образом на каждом (например, он пропускает ~/Library на 10,8, но показывает на 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 или ручное освобождение.

Если кто-то планирует поместить этот код в библиотеку, я настоятельно рекомендую сначала проверить pyobjc (import Foundation и, если вы не получите ImportError, вы выиграете), и использовать только ctypes код, если он недоступен.


Последнее примечание:

Некоторые люди, ищущие этот ответ, пытаются изобрести колесо, которое им не нужно.

Часто, когда люди делают что-то подобное, они создают графический интерфейс и хотят, например, показать файловые браузеры с возможностью скрыть или показать скрытые файлы. Многие популярные кроссплатформенные графические инфраструктуры (Qt, wx и т. Д.) Имеют встроенную поддержку. (Кроме того, многие из них имеют открытый исходный код, поэтому вы можете прочитать их код, чтобы узнать, как они это делают.)

Это может не отвечать на ваш вопрос - например, они могут просто передавать флаг «фильтровать скрытые файлы» в диалоговое окно браузера файлов на платформе, но вы пытаетесь создать файловый браузер в консольном режиме и можете ' сделать это. Но если это так, просто используйте его.

3 голосов
/ 12 ноября 2008

Мы на самом деле решаем эту проблему в проекте, который пишем. То, что мы делаем, - это несколько разных «контролеров скрытых файлов», которые зарегистрированы в основном контролере. Мы пропускаем каждый файл через них, чтобы понять, должен ли он быть скрыт или нет.

Эти контролеры предназначены не только для разных ОС и т. Д., Но мы подключаем к "игнорируемым" файлам контроля версий и необязательным пользовательским переопределениям с помощью glob или регулярного выражения.

В большинстве случаев это соответствует тому, что вы сделали, но гибким и расширяемым способом.

См. Исходный код здесь: https://bitbucket.org/aafshar/pida-main/src/tip/pida/services/filemanager/filemanager.py

0 голосов
/ 29 июня 2015

Включая мой предыдущий ответ, а также ответ @abarnert, я выпустил jaraco.path 1.1 с кросс-платформенной поддержкой для обнаружения скрытых файлов. С установленным пакетом, чтобы обнаружить скрытое состояние любого файла, просто вызовите is_hidden:

from jaraco import path
path.is_hidden(file)
0 голосов
/ 12 ноября 2008

"Есть ли стандартный способ справиться с этим?" Да. Используйте стандартную (т.е. POSIX-совместимую) ОС.

Так как Windows нестандартна - ну, - нет применимого стандарта. Не было бы замечательно, если бы было? Я чувствую твою боль.

Все, что вы пытаетесь сделать, кроссплатформенное, будет иметь странности Win32.

Ваше решение - на данный момент - превосходно. В какой-то момент в будущем Microsoft может решить написать POSIX-совместимую ОС. До этого вы хорошо справляетесь с ситуацией.

...