Обнаружение скрытых файлов кросс-платформенной

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

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

Ответы

Ответ 1

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

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

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

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

Ответ 2

Здесь script, который работает на 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.

Ответ 3

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

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

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

Попытка написать собственный код для обработки всего этого не будет простой. И вам нужно будет поддерживать его в актуальном состоянии, так как я готов поспорить, что черный список изменится с большинством версий ОС, информация Finder в конечном итоге перейдет от устаревших до полностью неподдерживаемых расширенных атрибутов, которые могут поддерживаться более широко, чем 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]

Это должно работать на любом 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-bit 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 и т.д.) Поддерживают эту поддержку. (Кроме того, многие из них имеют открытый исходный код, поэтому вы можете прочитать их код, чтобы посмотреть, как они это делают.)

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

Ответ 4

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

from jaraco import path
path.is_hidden(file)

Ответ 5

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

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

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

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