How to read or write the a s h r i file attributes on Windows using Python and ctypes?

前端 未结 1 1569
傲寒
傲寒 2021-01-21 23:26

For the records:

  • a means \'archivable\'
  • s means \'system\'
  • h means \'hidden\'
  • r mean
相关标签:
1条回答
  • 2021-01-22 00:24

    With the help of eriksuns comments to my question i solved it. Here is the code from my question but now using ctypes, stat and os.scandir. It requires Python 3.5+. Writes are ~50 times faster and reads are ~900 times faster.

    Python code:

    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()
    

    Output:

    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
    
    0 讨论(0)
提交回复
热议问题