如何使用Python和ctypes在Windows上读写a s h r文件属性?

记录:表示“可存档” s表示“系统” h表示“隐藏” r表示“只读”我的意思是“可索引的”我目前从Python脚本读取/写入这些属性的解决方案是使用subprocess模块调用attrib.Python代码:import os, subproces...

记录:

>表示“可存档”
> s表示“系统”
> h表示“隐藏”
> r表示“只读”
>我的意思是“可索引的”

我目前从Python脚本读取/写入这些属性的解决方案是使用subprocess模块调用attrib.

Python代码:

import os, subprocess

def attrib(path, a=None, s=None, h=None, r=None, i=None):
    attrs=[]
    if r==True:    attrs.append('+R')
    elif r==False: attrs.append('-R')
    if a==True:    attrs.append('+A')
    elif a==False: attrs.append('-A')
    if s==True:    attrs.append('+S')
    elif s==False: attrs.append('-S')
    if h==True:    attrs.append('+H')
    elif h==False: attrs.append('-H')
    if i==True:    attrs.append('+I')
    elif i==False: attrs.append('-I')

    if attrs: # write attributes
        cmd = attrs
        cmd.insert(0,'attrib')
        cmd.append(path)
        cmd.append('/L')
        return subprocess.call(cmd, shell=False)

    else: # just read attributes
        output = subprocess.check_output(
            ['attrib', path, '/L'],
            shell=False, universal_newlines=True
        )[:9]
        attrs = {'A':False, 'S':False, 'H':False, 'R':False, 'I':False}
        for char in output:
            if char in attrs:
                attrs[char] = True
        return attrs

path = 'C:\\test\\'
for thing in os.listdir(path):
    print(thing, str(attrib(os.path.join(path,thing))))

输出:

archivable.txt {'A': True, 'I': False, 'S': False, 'H': False, 'R': False}
hidden.txt {'A': True, 'I': False, 'S': False, 'H': True, 'R': False}
normal.txt {'A': True, 'I': False, 'S': False, 'H': False, 'R': False}
readonly.txt {'A': True, 'I': False, 'S': False, 'H': False, 'R': True}
system.txt {'A': True, 'I': False, 'S': True, 'H': False, 'R': False}

但是,如果目录包含许多条目(每个条目一个子过程调用),则执行速度会很慢.

我不想使用win32api模块,因为我不想使用第三方模块依赖项.我也很好奇如何用ctypes.

我偶然发现了Hide Folders/ File with Python [closed]、Set “hide” attribute on folders in windows OS?和Python: Windows System File,但是我不清楚.特别是我不明白这些0x4 es 0x02 es是什么.你能解释一下吗?您可以举一个具体的代码示例吗?

解决方法:

借助eriksuns对我的问题的评论,我解决了它.这是我的问题中的代码,但现在使用ctypes、stat和os.scandir.它需要Python 3.5.写入速度快50倍,读取速度快900倍.

Python代码:

from ctypes import WinDLL, WinError, get_last_error
from stat import \
    FILE_ATTRIBUTE_ARCHIVE as A, FILE_ATTRIBUTE_SYSTEM as S, \
    FILE_ATTRIBUTE_HIDDEN as H, FILE_ATTRIBUTE_READONLY as R, \
    FILE_ATTRIBUTE_NOT_CONTENT_INDEXED as I
from os import scandir, stat

def example_usage():
    path = 'C:\\test\\'
    # https://docs.python.org/3/library/ctypes.html#ctypes.WinDLL
    kernel32 = WinDLL('kernel32', use_last_error=True)

    print('\njust read the ashri attributes:')
    # https://docs.python.org/3/library/os.html#os.DirEntry
    for entry in scandir(path):
        a,s,h,r,i = myattrib(kernel32, entry)
        print(entry.path, a,s,h,r,i)

    print("\nset the readonly attribute on each entry:")
    for entry in scandir(path):
        a,s,h,r,i = myattrib(kernel32, entry, r=True)
        print(entry.path, a,s,h,r,i)

    print("\nset attributes more than once on the same entry:")
    for entry in scandir(path):
        a,s,h,r,i = myattrib(kernel32, entry, a=False, s=False, h=False, r=False, i=False)
        print(entry.path, a,s,h,r,i)
        a,s,h,r,i = myattrib(kernel32, entry, update=True, a=True, s=True, h=True, r=True, i=True)
        print(entry.path, a,s,h,r,i)

# Use update=True when you call this function a second time on the same DirEntry object.
def myattrib(kernel32, entry, update=False, a=None, s=None, h=None, r=None, i=None):

    # get the file attributes as an integer.
    if not update: # faster
        attrs = entry.stat(follow_symlinks=False).st_file_attributes
    else: # slower but reflects changes
        # notice that this will raise a WinError Access denied on some entries,
        # for example C:\System Volume Information\
        attrs = stat(entry.path, follow_symlinks=False).st_file_attributes

    # construct the new attributes
    newattrs = attrs
    def set(attr, value):
        nonlocal newattrs
        # use '{0:032b}'.format(number) to understand what this does.
        if value is True: newattrs = newattrs | attr
        elif value is False: newattrs = newattrs & ~attr
    set(A, a)
    set(S, s)
    set(H, h)
    set(R, r)
    set(I, i if i is None else not i)
    # optional add more attributes here, see
    # https://docs.python.org/3/library/stat.html#stat.FILE_ATTRIBUTE_ARCHIVE

    # write the new attributes if they changed
    if newattrs != attrs:
        if not kernel32.SetFileAttributesW(entry.path, newattrs):
            raise WinError(get_last_error())

    # return an info tuple
    return (
        bool(newattrs & A),
        bool(newattrs & S),
        bool(newattrs & H),
        bool(newattrs & R),
        not bool(newattrs & I)
    )

if __name__ == '__main__':
    example_usage()

输出:

just read the ashri attributes:
C:\test\hidden.txt True False True False True
C:\test\normal.txt True False False False True
C:\test\readonly.txt True False False True True
C:\test\systemfile.txt True True False False True

set the readonly attribute on each entry:
C:\test\hidden.txt True False True True True
C:\test\normal.txt True False False True True
C:\test\readonly.txt True False False True True
C:\test\systemfile.txt True True False True True

set attributes more than once on the same entry:
C:\test\hidden.txt False False False False False
C:\test\hidden.txt True True True True True
C:\test\normal.txt False False False False False
C:\test\normal.txt True True True True True
C:\test\readonly.txt False False False False False
C:\test\readonly.txt True True True True True
C:\test\systemfile.txt False False False False False
C:\test\systemfile.txt True True True True True

本文标题为:如何使用Python和ctypes在Windows上读写a s h r文件属性?

基础教程推荐