Python: системный файл Windows

В python, как я могу определить файл, который является «системным файлом окна». Из командной строки я могу сделать это с помощью следующей команды:

ATTRIB "c:\file_path_name.txt"

Если в возврате есть символ «S», то это системный файл Windows. Я не могу понять эквивалент в питоне. Несколько примеров подобных запросов выглядят следующим образом:

Является ли файл доступным для записи?

import os

filePath = r'c:\testfile.txt'

if os.access(filePath, os.W_OK):
   print 'writable'
else:
   print 'not writable'

другой путь...

import os
import stat

filePath = r'c:\testfile.txt'

attr = os.stat(filePath)[0]
if not attr & stat.S_IWRITE:
   print 'not writable'
else:
   print 'writable'

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

Причина, по которой я хочу это сделать, заключается в том, что я использую os.walk для копирования файлов с одного диска на другой. Если бы был способ обойти дерево каталогов, игнорируя системные файлы, это тоже могло бы сработать.

Спасибо за чтение.



Вот решения, которые я придумал на основе ответа:

Использование win32api:

import win32api
import win32con

filePath = r'c:\test_file_path.txt'

if not win32api.GetFileAttributes(filePath) & win32con.FILE_ATTRIBUTE_SYSTEM:
   print filePath, 'is not a windows system file'
else:
   print filePath, 'is a windows system file'

и используя ctypes:

import ctypes
import ctypes.wintypes as types

# From pywin32
FILE_ATTRIBUTE_SYSTEM = 0x4

kernel32dll = ctypes.windll.kernel32


class WIN32_FILE_ATTRIBUTE_DATA(ctypes.Structure):
   _fields_ = [("dwFileAttributes", types.DWORD),
               ("ftCreationTime", types.FILETIME),
               ("ftLastAccessTime", types.FILETIME),
               ("ftLastWriteTime", types.FILETIME),
               ("nFileSizeHigh", types.DWORD),
               ("nFileSizeLow", types.DWORD)]

def isWindowsSystemFile(pFilepath):
   GetFileExInfoStandard = 0

   GetFileAttributesEx = kernel32dll.GetFileAttributesExA
   GetFileAttributesEx.restype = ctypes.c_int
   # I can't figure out the correct args here
   #GetFileAttributesEx.argtypes = [ctypes.c_char, ctypes.c_int, WIN32_FILE_ATTRIBUTE_DATA]

   wfad = WIN32_FILE_ATTRIBUTE_DATA()
   GetFileAttributesEx(pFilepath, GetFileExInfoStandard, ctypes.byref(wfad))

   return wfad.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM

filePath = r'c:\test_file_path.txt'

if not isWindowsSystemFile(filePath):
   print filePath, 'is not a windows system file'
else:
   print filePath, 'is a windows system file'

Интересно, допустима ли вставка константы «FILE_ATTRIBUTE_SYSTEM» в мой код, или я могу также получить ее значение с помощью ctypes?


person stev    schedule 01.05.2013    source источник
comment
Вы всегда можете выполнить системную команду через python и вызвать ATTRIB   -  person Jesus Ramos    schedule 02.05.2013
comment
Я попробовал это как обходной путь, но проверка каждого файла делала его очень медленным.   -  person stev    schedule 02.05.2013
comment
Обычно вам действительно приходится вставлять константу FILE_ATTRIBUTE_SYSTEM в свой код таким образом. В Windows библиотеки DLL почти никогда не экспортируют константные символы, а только функции. (В POSIX общие объекты часто экспортируют символы, но большинство значений, которые вам нужны, в любом случае оказываются #define макросами, а не символами…)   -  person abarnert    schedule 02.05.2013
comment
В качестве примечания, вместо if not wfad.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM: return False else: return True, почему бы не просто return wfad.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM? (Если вам нужны фактические True/False, просто добавьте к ним != 0 или bool(…)… но на самом деле вашему коду не должно быть важно, получит ли он True или 4, так как они оба одинаково правдивы.)   -  person abarnert    schedule 02.05.2013
comment
И последнее замечание: обычно рекомендуется устанавливать argtypes и restypes для любых ctypes функций. Таким образом, Python может автоматически преобразовывать ваши аргументы, если это возможно, и вызывать исключение, если они не имеют смысла. Таким образом, вам придется вручную преобразовывать ваши аргументы, и если вы сделаете это неправильно, вы получите труднопонятное исключение (если вам повезет и вы работаете в Windows) или сбой (если вам не повезет или нет). в Windows).   -  person abarnert    schedule 02.05.2013
comment
Ах, хороший момент о том, что не нужно возвращать логическое значение. Я исправил это. Последнее, что я не могу понять, это argtypes. Это просто игра в угадайку? Подпись функции в MSDN, похоже, мало помогает.   -  person stev    schedule 02.05.2013


Ответы (1)


Но я не могу найти функцию или перечисление для идентификации системного файла Windows. Надеюсь, есть встроенный способ сделать это.

Такого нет. Абстракция файла Python не имеет понятия «системный файл», поэтому она не дает вам никакого способа его получить. Кроме того, Python stat представляет собой очень тонкую оболочку функций stat или _stat в библиотеке времени выполнения Microsoft C, которая не имеет понятия «системный файл». Причина этого в том, что и файлы Python, и библиотека Microsoft C спроектированы так, чтобы быть «почти похожими на POSIX».

Конечно, Windows также имеет совершенно другую абстракцию для файлов. Но это не раскрывается функциями open, stat и т. д.; скорее, есть полностью параллельный набор функций, таких как CreateFile, GetFileAttributes и т. д. И вы должны вызывать их, если хотите получить эту информацию.

Я бы предпочел не использовать win32com или другой внешний модуль.

Ну, вам не нужен win32com, потому что это просто Windows API, а не COM.

Но win32api это самый простой способ сделать это. Он обеспечивает удобную оболочку вокруг GetFileAttributesEx , то есть функцию, которую вы хотите вызвать.

Если вы не хотите использовать внешний модуль, вы всегда можете вызывать функции Windows API через ctypes вместо этого. Или используйте subprocess для запуска инструментов командной строки (например, ATTRIB — или, если вы предпочитаю, например, DIR /S /A-S, чтобы Windows выполняла часть рекурсивного пропуска системных файлов за вас…).

Документы ctypes показывают, как вызывать функции Windows API, но в первый раз это немного сложно.

Сначала вам нужно перейти на страницу MSDN, чтобы узнать, какую DLL вам нужно загрузить (kernel32), и есть ли у вашей функции отдельные варианты A и W (есть), и какие значения передавать для каких-либо констант (вы должны следовать ссылку на другую страницу и знать, как работают перечисления C, чтобы узнать, что GetFileExInfoStandard равно 0), а затем вам нужно выяснить, как определить любые необходимые structs. В этом случае что-то вроде этого:

from ctypes import *
kernel = windll.kernel32

GetFileExInfoStandard = 0

GetFileAttributesEx = kernel.GetFileAttributesEx
GetFileAttributesEx.restype = c_int
GetFileAttributesEx.argypes = # ...

Если вы действительно хотите избежать использования win32api, вы можете выполнить работу по завершению оболочки ctypes самостоятельно. Лично я бы использовал win32api.


Тем временем:

Причина, по которой я хочу это сделать, заключается в том, что я использую os.walk для копирования файлов с одного диска на другой. Если бы был способ обойти дерево каталогов, игнорируя системные файлы, это тоже могло бы сработать.

В этом случае, особенно с учетом вашей жалобы на слишком медленную проверку каждого файла, вы, вероятно, тоже не захотите использовать os.walk. Вместо этого используйте FindFirstFileEx и выполнить рекурсию вручную. Вы можете различать файлы и каталоги без необходимости stat (или GetFileAttributesEx) каждого файла (что os.walk делает скрытно), вы можете отфильтровывать системные файлы непосредственно внутри функции поиска вместо stat каждого файла и т. д.

Опять же, варианты те же: используйте win32api, если вы хотите, чтобы это было легко, используйте ctypes в противном случае.

Но в этом случае я бы взглянул на betterwalk Бена Хойта, потому что он уже сделал 99% ctypes-обертка и 95% остального кода, который вы хотите.

person abarnert    schedule 01.05.2013
comment
Отличный ответ, спасибо! Я попробую сделать это в обоих направлениях и опубликую свои решения. Я бы предпочел сделать это просто с помощью win32api, но это может быть вне моего контроля. Спасибо. - person stev; 02.05.2013