
go 中 `os.write` 返回的错误通常是 `*os.patherror`,需通过类型断言提取其 `err` 字段,并与 `syscall.enospc` 比较,才能可靠识别磁盘满错误。
在 Go 语言中,底层系统调用失败时,标准库(如 os.File.Write)不会直接返回 syscall.Errno 类型错误,而是封装为更语义化的 *os.PathError。该结构体包含操作名、路径及底层系统错误 Err 字段——而这个 Err 才可能是 syscall.Errno。
因此,正确检测 ENOSPC 的方式是:先对 err 进行 *os.PathError 类型断言,再检查其 Err 字段是否等于 syscall.ENOSPC。以下为修正后的完整示例:
package main
import (
"log"
"os"
"syscall"
)
func main() {
fd, err := os.Create("dump.txt")
if err != nil {
log.Fatal("failed to create file:", err)
}
defer fd.Close()
for {
buf := make([]byte, 1024)
_, err := fd.Write(buf)
if err != nil {
log.Printf("Write error: %v", err)
// 正确方式:断言 *os.PathError,再检查其 Err 字段
if pathErr, ok := err.(*os.PathError); ok {
if errno, ok := pathErr.Err.(syscall.Errno); ok && errno == syscall.ENOSPC {
log.Println("❌ Critical: No space left on device (ENOSPC)")
return
}
}
// 可选:处理其他常见系统错误(如权限不足、设备忙等)
log.Printf("Unexpected error type: %T, value: %v", err, err)
return
}
}
}✅ 关键点说明:
- err.(*os.PathError) 是第一层断言,因为 os.Write 在文件操作失败时几乎总是返回此类型;
- pathErr.Err 是嵌套的底层错误,需再次断言为 syscall.Errno 才能进行数值比较;
- 直接 err.(syscall.Errno) 失败(如原问题中所示),是因为 err 并非裸 syscall.Errno,而是被 os.PathError 包装过;
- 建议始终检查两次断言结果(ok),避免 panic;
⚠️ 注意事项:
- syscall.ENOSPC 是 Unix/Linux/macOS 常用常量;在 Windows 上对应错误码为 syscall.ERROR_HANDLE_DISK_FULL 或 syscall.ERROR_DISK_FULL,但 Go 标准库通常会统一映射为 ENOSPC(自 Go 1.13+ 起,os.IsNoSpace 已提供跨平台抽象);
- 更推荐的现代写法(Go 1.13+):使用 errors.Is(err, syscall.ENOSPC) 或 os.IsNoSpace(err),它内部已自动处理包装层级:
if os.IsNoSpace(err) {
log.Println("Out of disk space — handle gracefully")
}该方法更简洁、可读性强,且具备跨平台兼容性,是当前最佳实践。










