如何在Python中跨Windows、macOS、Linux获取用户文档文件夹(含自定义路径)
跨平台获取用户文档文件夹(支持自定义路径)
好问题!跨平台获取用户的文档目录确实得兼顾默认路径和用户自定义的情况,我来给你梳理下macOS和Linux的实现方案,再整合Windows的逻辑,凑个完整的跨平台解决方案~
Windows 实现(补充你已有的方案)
Windows下要获取用户修改后的文档路径,最靠谱的是调用系统原生API,而不是硬编码默认路径。这里给两种常用实现:
- 用
pywin32库(更简洁):
from win32com.client import Dispatch shell = Dispatch("WScript.Shell") documents_path = shell.SpecialFolders("MyDocuments")
- 依赖标准库
ctypes(无需额外安装):
import ctypes from ctypes import wintypes CSIDL_PERSONAL = 5 # 文档文件夹的系统标识 SHGFP_TYPE_CURRENT = 0 # 获取当前实际路径(而非默认) buf = wintypes.LPWSTR() ctypes.windll.shell32.SHGetFolderPathW(None, CSIDL_PERSONAL, None, SHGFP_TYPE_CURRENT, ctypes.byref(buf)) documents_path = buf.value ctypes.windll.kernel32.LocalFree(buf)
这两种方式都能准确返回用户手动修改后的文档路径。
macOS 实现
macOS下用户修改文档位置后,不能直接拼接/Users/<user>/Documents,得调用系统API来获取:
方法1:用pyobjc调用AppKit框架(推荐)
先安装依赖:pip install pyobjc
from AppKit import NSWorkspace def get_macos_documents_path(): # 调用系统API获取文档目录URL docs_url = NSWorkspace.sharedWorkspace().URLForDirectory_inDomain_appropriateForURL_create_error_( 9, # NSDocumentDirectory 对应的枚举值 1, # NSUserDomainMask:当前用户域 None, False, None ) return docs_url.path() if docs_url else None
方法2:用osascript调用AppleScript(无需额外依赖)
如果不想安装pyobjc,可以通过执行AppleScript来获取:
import subprocess def get_macos_documents_path(): result = subprocess.run( ['osascript', '-e', 'tell application "Finder" to get POSIX path of (path to documents folder)'], capture_output=True, text=True ) if result.returncode == 0: return result.stdout.strip() return None
Linux 实现
Linux遵循XDG规范,用户修改文档路径后会存在~/.config/user-dirs.dirs文件中,或者可以用xdg-user-dir命令直接获取:
方法1:调用xdg-user-dir命令(推荐)
大部分主流发行版都预装了这个工具,直接调用即可:
import subprocess def get_linux_documents_path(): result = subprocess.run( ['xdg-user-dir', 'DOCUMENTS'], capture_output=True, text=True ) if result.returncode == 0: return result.stdout.strip() # 命令失败时 fallback到默认路径 import os return os.path.expanduser('~/Documents')
方法2:读取user-dirs.dirs文件解析
如果系统没有xdg-user-dir,可以直接读取配置文件:
import os def get_linux_documents_path(): user_dirs_file = os.path.expanduser('~/.config/user-dirs.dirs') if os.path.exists(user_dirs_file): with open(user_dirs_file, 'r') as f: for line in f: line = line.strip() if line.startswith('XDG_DOCUMENTS_DIR='): # 去掉引号并替换$HOME为实际用户目录 path = line.split('=')[1].strip('"') return os.path.expanduser(path) # fallback到默认路径 return os.path.expanduser('~/Documents')
跨平台整合函数
把上面的逻辑整合到一个函数里,自动适配不同系统:
import os import sys def get_user_documents_path(): if sys.platform.startswith('win32'): # Windows分支 try: from win32com.client import Dispatch shell = Dispatch("WScript.Shell") return shell.SpecialFolders("MyDocuments") except ImportError: # 用ctypes作为备选 import ctypes from ctypes import wintypes CSIDL_PERSONAL = 5 SHGFP_TYPE_CURRENT = 0 buf = wintypes.LPWSTR() ctypes.windll.shell32.SHGetFolderPathW(None, CSIDL_PERSONAL, None, SHGFP_TYPE_CURRENT, ctypes.byref(buf)) path = buf.value ctypes.windll.kernel32.LocalFree(buf) return path elif sys.platform.startswith('darwin'): # macOS分支 try: from AppKit import NSWorkspace docs_url = NSWorkspace.sharedWorkspace().URLForDirectory_inDomain_appropriateForURL_create_error_( 9, 1, None, False, None ) return docs_url.path() if docs_url else os.path.expanduser('~/Documents') except ImportError: # 用osascript作为备选 import subprocess result = subprocess.run( ['osascript', '-e', 'tell application "Finder" to get POSIX path of (path to documents folder)'], capture_output=True, text=True ) if result.returncode == 0: return result.stdout.strip() return os.path.expanduser('~/Documents') elif sys.platform.startswith('linux'): # Linux分支 try: import subprocess result = subprocess.run(['xdg-user-dir', 'DOCUMENTS'], capture_output=True, text=True) if result.returncode == 0: return result.stdout.strip() except (subprocess.CalledProcessError, FileNotFoundError): pass # 读取配置文件作为备选 user_dirs_file = os.path.expanduser('~/.config/user-dirs.dirs') if os.path.exists(user_dirs_file): with open(user_dirs_file, 'r') as f: for line in f: line = line.strip() if line.startswith('XDG_DOCUMENTS_DIR='): path = line.split('=')[1].strip('"') return os.path.expanduser(path) return os.path.expanduser('~/Documents') else: # 未知平台返回默认路径 return os.path.expanduser('~/Documents') # 测试调用 print(get_user_documents_path())
内容的提问来源于stack exchange,提问作者Vishal




