可行,但需显式提供凭据、正确设置协议版本与加密参数,并使用标准UNC路径;默认不支持Windows凭据继承,易因权限、配置或网络策略报错。

直接用 smbprotocol 连 SMB 共享文件夹是可行的,但默认不支持 Windows 凭据自动继承(比如当前登录用户),必须显式提供用户名/密码或 Kerberos 票据;且路径格式、权限错误、服务器配置差异极易导致 ConnectionRefusedError 或 SessionError: STATUS_LOGON_FAILURE。
安装与基础连接:确认协议版本和认证方式
smbprotocol 默认尝试 SMBv3,但很多 NAS 或老 Windows 服务器只开 SMBv2 或禁用签名,连不上时先查服务端支持的协议版本。另外,它不读取系统凭据管理器,username 不能省略为 None 或空字符串,否则会触发匿名登录失败。
- 安装命令:
pip install smbprotocol(注意不是pysmb) - 连接时必须指定
username和password,域用户写成DOMAINuser或user@DOMAIN - 若服务器禁用 SMB 签名,需加参数
encrypt=False, require_encryption=False - 超时建议显式设为
timeout=15,避免卡死在 DNS 解析或防火墙拦截上
列出共享目录内容:注意 UNC 路径与驱动器映射无关
不要用本地映射的盘符(如 Z:older),smbprotocol 只认标准 UNC 格式:\\server\share\path。反斜杠要双写或用原始字符串,否则 Python 会误解析转义符。
- 正确写法:
r"\192.168.1.100\Public\docs"或"\\192.168.1.100\Public\docs" -
tree_connect对应共享名(Public),create_directory/list_path的path是共享内的相对路径 - 列出文件用
tree.list_path('', '*'),其中第一个参数是子目录(空字符串表示根),第二个是通配符 - 返回的
FileEntry对象里,file_name是名字,is_directory判断类型,creation_time等字段需手动转换时区
下载文件到本地:避免内存溢出和权限拒绝
大文件直接用 tree.open_file() + read() 会全载入内存,容易 OOM;而 shutil.copyfileobj() 流式读写更安全。另外,Windows 共享常对“创建时间”“最后访问时间”有写权限要求,单纯读文件一般没问题,但若调用 set_file_info 就可能报 STATUS_ACCESS_DENIED。
立即学习“Python免费学习笔记(深入)”;
- 打开文件用
open_file(path, CreateDisposition.FILE_OPEN, DesiredAccess.GENERIC_READ) - 分块读写示例:
while chunk := file_obj.read(8192): f.write(chunk) - 目标本地路径需确保父目录存在,
os.makedirs(os.path.dirname(local_path), exist_ok=True) - 若服务器启用了“SMB 加密强制”,客户端必须设
encrypt=True,否则连接成功但读文件时报InvalidParameter
常见报错与绕过思路
很多问题不是代码写错,而是服务端策略或网络中间件干扰。比如公司内网常部署 SMB 中间代理,会重写 ServerName,导致证书校验失败;又或者防火墙只放行 445 端口但屏蔽了 NetBIOS 相关的 137–139 端口(虽 SMBv2+ 不依赖,但某些 NAS 厂商实现仍会探测)。
-
NTStatusError: STATUS_BAD_NETWORK_NAME→ 检查共享名拼写,确认服务器已启用 SMB 共享(非仅 FTP/NFS) -
NTStatusError: STATUS_IO_TIMEOUT→ 改用 IP 地址而非主机名,排除 DNS 问题;或加connection_timeout=30 -
NTStatusError: STATUS_NOT_SUPPORTED→ 服务端禁用 SMBv3,降级尝试dialects=[Dialects.SMB_2_1] - 始终连不上?抓包看是否卡在 Session Setup Request 阶段 —— 很可能是密码含特殊字符未 URL 编码,或域控策略限制 NTLMv2
最麻烦的其实是 Kerberos 认证场景:需要提前 kinit,且 smbprotocol 要求 auth_protocol='kerberos' 并设置 username 为 UPN 格式,稍有不匹配就退回到 NTLM 并失败。这种情况下,与其硬调,不如先用 net use 映射再走本地路径,反而更稳。


















