如何在 Go 中准确判断 write 操作因磁盘空间不足(ENOSPC)而失败

11次阅读

如何在 Go 中准确判断 write 操作因磁盘空间不足(ENOSPC)而失败

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") }

该方法更简洁、可读性强,且具备跨平台兼容性,是当前最佳实践。

text=ZqhQzanResources