【问题标题】:Python: Windows System FilePython:Windows 系统文件
【发布时间】:2013-04-25 22:30:22
【问题描述】:

在 python 中,我如何识别一个文件是“窗口系统文件”。在命令行中,我可以使用以下命令执行此操作:

ATTRIB "c:\file_path_name.txt"

如果返回有“S”字符,那么它是一个windows系统文件。我无法弄清楚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'

但我找不到用于识别 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 获取它的值?

【问题讨论】:

  • 你可以随时通过python执行系统命令并调用ATTRIB
  • 我尝试将其作为一种解决方法,但必须检查每个文件使其非常慢。
  • 通常情况下,事实上,您必须像这样将常量FILE_ATTRIBUTE_SYSTEM 粘贴到您的代码中。在 Windows 上,DLL 几乎从不导出常量符号,只导出函数。 (在 POSIX 上,共享对象经常导出符号,但您想要的大多数值都是#define 宏而不是符号……)
  • 附带说明,而不是if not wfad.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM: return False else: return True,为什么不只是return wfad.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM? (如果您需要实际的True/False,只需在其上添加!= 0bool(…)……但实际上,您的代码不应该关心它是得到True 还是4,因为它们是两者都同样真实。)
  • 最后一条评论:在任何ctypes 函数上设置argtypesrestypes 通常是个好主意。这样,如果可能,Python 可以自动转换您的参数,并在它们没有意义时引发异常。这样,你必须手动转换你的参数,如果你做错了,你会得到一个难以理解的异常(如果你幸运并且在 Windows 上)或崩溃(如果你不走运,或者不是在 Windows 上)。

标签: python windows file system stat


【解决方案1】:

但我找不到用于识别 Windows 系统文件的函数或枚举。希望有一种内置的方法可以做到这一点。

没有这样的事情。 Python 的文件抽象没有任何“系统文件”的概念,所以它没有给你任何获取它的方法。此外,Python 的 stat 是微软 C 运行时库中 stat_stat 函数的一个非常薄的包装器,它没有任何“系统文件”的概念。原因是 Python 文件和 Microsoft 的 C 库都被设计为“非常像 POSIX”。

当然,Windows对文件有完全不同的抽象。但是这个没有被openstat等函数暴露出来;相反,有一组完全并行的函数,例如 CreateFileGetFileAttributes 等。如果您需要这些信息,则必须调用它们。

我宁愿不必使用 win32com 或其他外部模块。

好吧,你不需要win32com,因为这只是 Windows API,而不是 COM。

但是win32api 是最简单的方法。它为GetFileAttributesEx 提供了一个很好的包装器,这是您要调用的函数。

如果您不想使用外部模块,您可以随时通过 ctypes 调用 Windows API 函数。或者使用subprocess 来运行命令行工具(比如ATTRIB——或者,如果你愿意,比如DIR /S /A-S 让Windows 为你做recursive-walk-skipping-system-files 位......)。

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 在幕后做的),您可以直接在 find 函数中过滤掉系统文件,而不必stat 每个文件等

同样,选项是相同的:如果您希望它更简单,请使用 win32api,否则使用 ctypes

但在这种情况下,我会看看 Ben Hoyt 的 betterwalk,因为他已经完成了 99% 的 ctypes-wrapping 和 95% 的其余代码,这是你想要的。

【讨论】:

  • 很好的答案,谢谢!我将尝试两种方式并发布我的解决方案。我更喜欢简单地使用 win32api 来完成,但这可能超出我的控制范围。谢谢。
猜你喜欢
  • 1970-01-01
  • 2018-04-10
  • 2016-09-21
  • 2016-05-08
  • 2013-04-28
  • 2010-10-05
  • 2015-08-07
  • 1970-01-01
  • 2019-11-11
相关资源
最近更新 更多