
windows 文件系统不使用 unix 风格的 uid,而是通过安全标识符(sid)标识文件所有者;go 标准库不直接支持获取 sid,需借助 win32 api 或第三方封装包实现。
windows 文件系统不使用 unix 风格的 uid,而是通过安全标识符(sid)标识文件所有者;go 标准库不直接支持获取 sid,需借助 win32 api 或第三方封装包实现。
在类 Unix 系统(如 Linux/macOS)中,os.FileInfo.Sys() 可返回 syscall.Stat_t,从中可提取 Uid 字段——这是 POSIX 文件权限模型的一部分。然而,Windows 并无“UID”概念:其安全模型基于 NTFS 的访问控制列表(ACL)和安全标识符(SID),每个用户或组由唯一、不可重复解析的 SID(如 S-1-5-21-...)标识,而非数值型 UID。
因此,当你调用 fi.Sys() 在 Windows 上时,返回值通常是 *syscall.Win32FileAttributeData 或 *syscall.Win32FindData,不包含所有者 SID。标准库 os 和 syscall 包未提供跨平台获取文件所有者的接口,也未封装 GetSecurityInfo 或 GetNamedSecurityInfo 等关键 Win32 API。
✅ 正确做法是调用 Windows 原生 API 获取文件安全描述符,并从中提取所有者 SID。推荐使用成熟封装库,例如 golang.org/x/sys/windows(官方维护)配合手动调用,或更便捷的第三方包:
// 示例:使用 github.com/StackExchange/wmi(仅限 WMI,不推荐用于文件所有权)
// 更推荐:github.com/josephspurrier/winapi-go (轻量) 或直接使用 x/sys/windows
package main
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
func getFileOwner(path string) (string, error) {
var secDesc *windows.SECURITY_DESCRIPTOR
err := windows.GetNamedSecurityInfo(
windows.StringToUTF16Ptr(path),
windows.SE_FILE_OBJECT,
windows.OWNER_SECURITY_INFORMATION,
nil, // owner
nil, // group
nil, // dacl
nil, // sacl
&secDesc,
)
if err != nil {
return "", err
}
defer windows.LocalFree(syscall.Handle(unsafe.Pointer(secDesc)))
var ownerSid *windows.SID
var ownerDefaulted uint32
if err = windows.GetSecurityDescriptorOwner(secDesc, &ownerSid, &ownerDefaulted); err != nil {
return "", err
}
if ownerSid == nil {
return "(no owner)", nil
}
// 将 SID 转为可读字符串(如 "S-1-5-21-...")
sidStr, err := windows.ConvertSidToStringSid(ownerSid)
if err != nil {
return "", err
}
return sidStr, nil
}
func main() {
sid, err := getFileOwner(`C:\Windows\notepad.exe`)
if err != nil {
panic(err)
}
fmt.Println("File owner SID:", sid)
}⚠️ 注意事项:
- 必须以管理员或具有“读取所有属性”权限的用户身份运行,否则 GetNamedSecurityInfo 可能返回 ERROR_ACCESS_DENIED;
- 某些文件(如重定向卷、网络驱动器、FAT32 卷)不支持 ACL,将无所有者信息;
- ConvertSidToStringSid 返回的 SID 字符串不可直接映射到用户名——如需显示用户名,需额外调用 LookupAccountSid;
- 不建议自行解析 SID 二进制结构,应始终使用 windows 包提供的转换函数。
? 总结:
Windows 下不存在“文件 UID”,取而代之的是 SID;Go 标准库不提供开箱即用的获取方式,但可通过 golang.org/x/sys/windows 安全调用 Win32 API 实现。生产环境建议封装为复用函数,并妥善处理权限、空 SID 和错误边界。


















