For the records:
a
means \'archivable\'s
means \'system\'h
means \'hidden\'r
mean
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