Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I check for specific types of error among those returned by ioutil.ReadFile?

Tags:

go

When I use ioutil to read a file, it may return an error. But if I want to filter some error code, what should I do?

res, err := ioutil.ReadFile("xxx")
if err != nil {
    fmt.Println(err.Error())  
}
...

In the code snippet above, when a file has no permission, fmt.Println(err.Error()) will print "open xxxxx: permission denied. If I want to capture this kind error, how can I know that file read failed because permission was denied?

Should I search err.Error() for the string permission denied - this looks ungraceful. Is there any better way?

Thanks in advance.

Update

After trying @Intermernet solution, I found that it will not hit case os.ErrPermission, it will hit default and print "open xxx: Permission denied".

@Aedolon solution is ok, os.IsPermission(err) can tell that a file has failed with permission deny.

like image 338
Jerry YY Rain Avatar asked May 04 '14 03:05

Jerry YY Rain


2 Answers

According to the current API, ioutil.ReadFile doesn't guarantee any specific behaviour except that it will return err == nil when successful. Even the syscall package doesn't actually guarantee a specific error.

The current implementation of ioutil.ReadFile uses os.Open, which will return *os.PathError when failing to open a file, not os.ErrPermission or anything else. os.PathError contains a field Err which is also an error - in this case, a syscall.Errno. The string "permission denied" is produced from a private table of error messages and it's both architecture and implementation-specific. In my Windows machine it says "Access is denied" instead.

AFAIK, the correct method is to use os.IsPermission(err), which will return true in case of lacking permissions.

like image 61
LemurFromTheId Avatar answered Sep 25 '22 07:09

LemurFromTheId


Per documentation, errors returned should be tested against these errors using errors.Is

var (
// ErrInvalid indicates an invalid argument.
// Methods on File will return this error when the receiver is nil.
ErrInvalid = errInvalid() // "invalid argument"

ErrPermission = errPermission() // "permission denied"
ErrExist      = errExist()      // "file already exists"
ErrNotExist   = errNotExist()   // "file does not exist"
ErrClosed     = errClosed()     // "file already closed"
ErrNoDeadline = errNoDeadline() // "file type does not support deadline"
)

As an example:

f, err := ioutil.ReadFile("your_file")

if err != nil {
    if errors.Is(err, os.ErrNotExist) {
        // your code
    } else if errors.Is(err, os.ErrPermission) {
        // your code
    } else {
        panic(err)
    }
}
like image 42
Evaldo Neto Avatar answered Sep 23 '22 07:09

Evaldo Neto