调用后获取操作系统错误的惯用方式

huangapple go评论112阅读模式
英文:

idiomatic way to get os err after call

问题

如果我执行以下代码:

s, err := os.Stat(path)

并且 err != nil,我需要知道是文件不存在还是我没有权限访问等等。我该如何获取底层的错误代码?阅读 os 包的文档,似乎建议我读取错误字符串的文本 - 这真的是这样吗?

英文:

If I do

s, err := os.Stat(path)

and err != nil I need to know if the file doesn't exist vs I don't have permission to access it, etc. How do I get the underlying error code? Reading the os package docs it seems to suggest that I read the text of the error string - surely not?

答案1

得分: 6

【FUZxxl说】。

os.Stat文档中:

> Stat返回描述指定文件的FileInfo如果发生错误,它将是*PathError类型。

PathError同一页上有文档,说明它保存了导致错误的操作、导致错误的文件路径和底层系统的错误。如果在调用os.Stat时找不到文件,返回的错误可能是这样的:

&PathError{"stat", "/your/file", syscall.Errno(2)}

由于底层错误本质上取决于您使用的操作系统,您唯一能做的就是理解PathError.Err。对于UNIX系统,syscall包具有由诸如syscall.Stat之类的系统调用返回的Errno错误类型。您可以将此值与syscall包中的常量进行比较并处理错误(点击播放):

stat, err := os.Stat(file)

if perr, ok := err.(*os.PathError); ok {
    switch perr.Err.(syscall.Errno) {
         case syscall.ENOENT: fmt.Println("No such file or directory.")
         default: panic("Unknown error")
    }
}

更简洁的方法是使用os.IsNotExist,它实际上就是上述操作,而且最重要的是与平台无关:

stat, err := os.Stat(file)

if err != nil && os.IsNotExist(err) {
    // ...
}
英文:

What FUZxxl says.

From the os.Stat documentation:

> Stat returns a FileInfo describing the named file. If there is an error, it will be of type *PathError.

PathError is documented on the same page, stating that it holds the operation that caused the error, the path to the file that caused it and the underlying system's error. In case the file was not found when calling os.Stat, the returned error would be something like this:

&PathError{"stat", "/your/file", syscall.Errno(2)}

Since the underlying error is inherently depending on the OS you use, the only thing that you can do is to
understand PathError.Err. For UNIX systems the syscall package has the Errno error type returned by syscalls like syscall.Stat. You can compare this value with the constants in the syscall package and handle the error (Click to play):

stat, err := os.Stat(file)

if perr, ok := err.(*os.PathError); ok {
    switch perr.Err.(syscall.Errno) {
         case syscall.ENOENT: fmt.Println("No such file or directory.")
         default: panic("Unknown error")
    }
}

The shorter way of doing this is to use os.IsNotExist which does pretty much the above
and is, most importantly, platform independent:

stat, err := os.Stat(file)

if err != nil && os.IsNotExist(err) {
    // ...
}

答案2

得分: 1

另一个答案很好,但我想补充一下关于这个建议的说明:

stat, err := os.Stat(file)

if err != nil && os.IsNotExist(err) {
    // ...
}

我发现在许多情况下,我需要根据每个测试采取不同的操作,所以实际上你有三个分支。这是我用于处理这种情况的代码:

stat, err := os.Stat(file)

if os.IsNotExist(err) {
   // 第一个分支
} else if err != nil {
   // 第二个分支
}

// 第三个分支
英文:

The other answer is great, but I wanted add a note about this suggestion:

stat, err := os.Stat(file)

if err != nil && os.IsNotExist(err) {
    // ...
}

I found that in many cases, I was needing to take different actions depending on
each test, so in reality you have three branches here. Here is code I use for
that:

stat, err := os.Stat(file)

if os.IsNotExist(err) {
   // branch one
} else if err != nil {
   // branch two
}

// branch three

huangapple
  • 本文由 发表于 2014年6月5日 01:26:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/24043781.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定