如何在 Python 中检查文件夹的 'hidden' 属性?

How do I Check a Folder's 'hidden' Attribute in Python?

我正在开发一个 load/save 模块(用 Python 编写的 GUI),它将与未来的程序一起使用并导入。我的操作系统是 Windows 10。我 运行 遇到的问题是我的 get_folders() 方法正在获取所有文件夹名称,包括我宁愿忽略的文件夹名称,例如系统文件夹和隐藏文件夹(最好在 C 盘上看到)。

我有一个使用硬编码排除列表的解决方法。但这仅适用于已在列表中的文件夹,不适用于我的向导将来可能出现的隐藏文件夹 across。我想排除设置了 'hidden' 属性的 ALL 文件夹。我想避免需要安装新库的方法,这些库在我擦除系统时必须重新安装。此外,如果解决方案不是 Windows 特定的,但可以与 Windows 10 一起使用,那就更好了。

我在 SO 和网上搜索了答案,但一无所获。我找到的 closest 包含在该线程的答案 #4 中:Check for a folder, then create a hidden folder in Python,它显示了如何在创建新目录时设置隐藏属性,但没有显示如何读取隐藏属性现有目录。

这是我的问题:有谁知道使用本机 python、pygame 或 [=36= 来检查文件夹的 'hidden' 属性是否已设置的方法].命令?或者,如果没有本地答案,我会接受从实现我的目标的库中导入的方法。

以下程序演示了我的 get_folders() 方法,并显示了手头的问题:

# Written for Windows 10
import os
import win32gui

CLS = lambda :os.system('cls||echo -e \\033c') # Clear-Command-Console function

def get_folders(path = -1, exclude_list = -1):
    
    if path == -1: path = os.getcwd()    
    if exclude_list == -1: exclude_list = ["Config.Msi","Documents and Settings","System Volume Information","Recovery","ProgramData"]
    
    dir_list = [entry.name for entry in os.scandir(path) if entry.is_dir()] if exclude_list == [] else\
     [entry.name for entry in os.scandir(path) if entry.is_dir() and '$' not in entry.name and entry.name not in exclude_list]
    
    return dir_list

def main():
    
    HWND = win32gui.GetForegroundWindow()                 # Get Command Console Handle.
    win32gui.MoveWindow(HWND,100,50,650,750,False) # Size and Position Command Console.
    CLS()  # Clear Console Screen.
    
    print(''.join(['\n','Folder Names'.center(50),'\n ',('-'*50).center(50)]))
    
    # Example 1: Current Working Directory        
    dirs = get_folders()  # Get folder names in current directory (uses exclude list.)
    for elm in dirs:print(' ',elm)  # Show the folder names.
    print('','-'*50)

    # Examle 2: C Drive, All Folders Included
    dirs = get_folders('c:\', exclude_list = []) # Get a list of folders in the root c: drive, nothing excluded.
    for elm in dirs: print(' ',elm) # Show the fiolder names
    print('','-'*50)
    
    # Example 3: C Drive, Excluded Folder List Work-Around
    dirs = get_folders('c:\')      # Get a list of folders in the root c: drive, excluding sytem dirs those named in the exclude_list.
    for elm in dirs:print(' ',elm)   # Show the folder names.

    print("\n Question: Is there a way to identify folders that have the 'hidden' attribute\n\t set to True, rather than using a hard-coded exclusion list?",end='\n\n' )

# ==========================
if __name__ == "__main__": 
    main()
    input(' Press [Enter] to Quit: ')
    CLS()

这是我修改后的 get_folders() 方法,感谢 Alexander。

# Written for Windows 10
# key portions of this code borrowed from:
# 
# with thanks to Alexander Goryushkin.

import os
from os import scandir, stat
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 ctypes import WinDLL, WinError, get_last_error
import win32gui

CLS = lambda :os.system('cls||echo -e \\033c') # Clear-Command-Console function

def read_or_write_attribs(kernel32, entry,  a=None, s=None, h=None, r=None, i=None,  update=False):

    # Get the file attributes as an integer.
    if not update: attrs = entry.stat(follow_symlinks=False).st_file_attributes# Fast because we access the stats from the entry
    else:
        # 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
        # A bit slower because we re-read the stats from the file path.

    # Construct the new attributes
    newattrs = attrs
    def setattrib(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
              setattrib(A, a)
              setattrib(S, s)
              setattrib(H, h)
              setattrib(R, r)
              setattrib(I, i if i is None else not i)  # Because this attribute is True when the file is _not_ indexed

    # 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 consisting of bools
    return ( bool(newattrs & A), 
                   bool(newattrs & S), 
                   bool(newattrs & H), 
                   bool(newattrs & R), 
                   not bool(newattrs & I) )# Because this attribute is true when the file is _not_ indexed)

    # Get the file attributes as an integer.
    if not update:
        # Fast because we access the stats from the entry
        attrs = entry.stat(follow_symlinks=False).st_file_attributes
    else:
        # A bit slower because we re-read the stats from the file path.
        # 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
    return dir_list

def get_folders(path = -1, show_hidden = False):
        
    if path == -1: path = os.getcwd()    
    dir_list = []
    kernel32 = WinDLL('kernel32', use_last_error=True)
    for entry in scandir(path):
        a,s,hidden,r,i = read_or_write_attribs(kernel32,entry)
        
        if entry.is_dir() and (show_hidden or not hidden): dir_list.append(entry.name)
    return dir_list
    
def main():

    HWND = win32gui.GetForegroundWindow()                 # Get Command Console Handle.
    win32gui.MoveWindow(HWND,100,50,650,750,False) # Size and Position Command Console.
    CLS()  # Clear Console Screen.

    line_len = 36

    # Example 1: C Drive, Exclude Hidden Folders
    print(''.join(['\n','All Folders Not Hidden:'.center(line_len),'\n ',('-'*line_len).center(line_len)]))        
    dirs = get_folders('c:\')  # Get a list of folders on the c: drive, exclude hidden.
    for elm in dirs:print(' ',elm)  # Show the folder names.
    print('','='*line_len)

    # Examle 2: C Drive, Include Hidden Folders
    print("  All Folders Including Hidden\n "+"-"*line_len)
    dirs = get_folders('c:\', show_hidden = True) # Get a list of folders on the c: drive, including hidden.
    for elm in dirs: print(' ',elm) # Show the fiolder names
    print('','-'*line_len)
# ==========================
if __name__ == "__main__": 
    main()
    input(' Press [Enter] to Quit: ')
    CLS()