Go调用GetFileInformationByHandle时出现"The handle is invalid"错误排查
问题分析与修复方案
哦,我一眼就看到问题所在了——你完全误用了GetFileVersionInfoSize返回的那个所谓的"handle",它根本不是你需要的文件句柄!
错误原因详解
windows.GetFileVersionInfoSize的第二个参数&handle,这个参数的作用不是返回文件句柄,而是用来接收一个与版本信息资源相关的临时值(多数情况下,成功调用后这个值也只是给后续GetFileVersionInfo函数使用,和文件本身的句柄没有任何关系)。你初始化的handle变量默认是0,直接把这个无效值传给GetFileInformationByHandle,必然会触发"无效句柄"的错误。
修复方案
方案1:直接用windows.Open获取合法文件句柄
这是最直接的方式,通过Windows API打开文件并获取句柄,专门用于后续的文件信息查询:
package main import ( "log" "golang.org/x/sys/windows" ) func main() { name := `C:\Windows\System32\cmd.exe` // 以只读模式打开文件,设置合理的共享权限 handle, err := windows.Open( name, windows.GENERIC_READ, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, ) if err != nil { log.Fatalf("Failed to open file: %s", err.Error()) } defer windows.CloseHandle(handle) // 务必记得关闭句柄,避免资源泄漏 var hndlFileInfo windows.ByHandleFileInformation err = windows.GetFileInformationByHandle(handle, &hndlFileInfo) if err != nil { if err == windows.ERROR_INVALID_HANDLE { log.Println("Error is invalid handle error.") } log.Fatalf("GetFileInformationByHandle error: path: %s %s", name, err.Error()) } // 将Windows文件时间转换为Go标准时间格式 creationTime := windows.FiletimeToTime(hndlFileInfo.CreationTime) log.Printf("File creation time: %v", creationTime) log.Println("Success!") }
方案2:从已打开的os.File中获取底层句柄
如果你已经通过os包打开了文件,可以直接提取它的底层句柄来使用:
package main import ( "log" "os" "syscall" "golang.org/x/sys/windows" ) func main() { name := `C:\Windows\System32\cmd.exe` file, err := os.Open(name) if err != nil { log.Fatalf("Unable to open %s: %s", name, err.Error()) } defer file.Close() // 从os.File中提取底层的syscall句柄,转换为windows.Handle sysHandle := syscall.Handle(file.Fd()) handle := windows.Handle(sysHandle) var hndlFileInfo windows.ByHandleFileInformation err = windows.GetFileInformationByHandle(handle, &hndlFileInfo) if err != nil { if err == windows.ERROR_INVALID_HANDLE { log.Println("Error is invalid handle error.") } log.Fatalf("GetFileInformationByHandle error: path: %s %s", name, err.Error()) } creationTime := windows.FiletimeToTime(hndlFileInfo.CreationTime) log.Printf("File creation time: %v", creationTime) log.Println("Success!") }
额外注意事项
- 无论哪种方案,都要记得关闭文件句柄(用
defer语句确保退出前执行),防止系统资源泄漏。 GetFileVersionInfoSize的那个参数不要用来做文件句柄,它的唯一用途是配合GetFileVersionInfo获取文件版本信息,和文件本身的操作无关。
内容的提问来源于stack exchange,提问作者Shane Bishop
相关产品推荐
相关产品推荐

