2013-05-01 2 views
-1

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

ATTRIB "c:\file_path_name.txt" 

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

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

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' 

Но я не могу найти функцию или перечисление для идентификации окна системного файла. Надеюсь, есть встроенный способ сделать это. Я бы предпочел не использовать 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?

+1

Вы всегда можете выполнить системную команду через python и вызвать ATTRIB –

+1

Я пробовал это как обходной путь, но проверка каждого файла делала его очень медленным. – stev

+0

Обычно вам нужно вставить константу 'FILE_ATTRIBUTE_SYSTEM' в свой код. В Windows DLL почти никогда не экспортируют постоянные символы, просто функции. (В POSIX общие объекты часто _do_ экспортируют символы, но большинство значений, которые вы хотите, скорее всего являются макросами '# define', а не символами ...) – abarnert

ответ

1

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

Нет такой вещи. В абстракции файла Python нет понятия «системный файл», поэтому он не дает вам никакого способа получить его. Кроме того, Python stat - очень тонкая оболочка вокруг функций stat или _stat в библиотеке времени исполнения Microsoft, в которой нет понятия «системный файл». Причина этого заключается в том, что оба файла Python и C-библиотека Microsoft созданы так, чтобы быть «в значительной степени похожим на 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 enums, чтобы узнать, что GetFileExInfoStandard = 0), а затем вам нужно выяснить, как определить любые struct. В этом случае, что-то вроде этого:

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.

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

+0

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