I use some code similar to the lines below. The rename can fail if the directory is blocked because some application has a file open in it.
err := os.Rename("C:/temp/inUse", "c:/temp/Renamed")
if err != nil {
fmt.Println(err)
...
}
I am able to detect this fact when I check err
for this content:
rename C:/temp/inUse c:/temp/Renamed: Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.
(which translates to "The process is unable to access the file because it is used by a different process") But this message varies depending on the OS language.
Is it possible to detect the problem by a unique "error code" ? I wouldn't mind if the solution is specific to Windows and doesn't work on other operating systems supported by Go.
Ideally I could do something like if err.Err == 32 { fmt.Println( "Your directory is in use please ...
The error returned by os.Rename
is of type *os.LinkError
which gives you access to the underlying error from the operating system. You should be able to use that to distinguish the particular error you are encountering.
You'll need to convert the error to *os.LinkError first.
For instance, trying to rename a folder (/Users/t/pprof
) to another name that is write-protected (/Users/t/pprof2
):
func TestRename(t *testing.T) {
err := os.Rename("/Users/t/pprof", "/Users/t/pprof2")
if err != nil {
e := err.(*os.LinkError)
t.Logf("Op: ", e.Op)
t.Logf("Old: ", e.Old)
t.Logf("New: ", e.New)
t.Logf("Err: ", e.Err)
}
}
Provides the following output:
Op: %!(EXTRA string=rename)
Old: %!(EXTRA string=/Users/t/pprof)
New: %!(EXTRA string=/Users/t/pprof2)
Err: %!(EXTRA syscall.Errno=operation not permitted)
The OS error code is accessible as the Err
member, but will be different depending on the OS you are running.
The Err
member is of type syscall.Errno
. To further inspect the actual error, you need to convert it to that type first:
oserr := e.Err.(syscall.Errno)
Now oserr
can be compared with the values for Errno
declared in the syscall
package. You'll find them if you search for ENOENT
on that page.
For instance, you can check for your particular error by doing:
switch oserr {
case syscall.ENOENT:
// Handle this error
default:
// Handle other errors
}
}
In general, it's very convenient to use fmt.Printf when debugging these sort of issues. In the example above:
fmt.Println(err)
prints
rename /Users/t/pprof /Users/t/pprof2: operation not permitted
where-as
fmt.Printf("%#v\n", err)
prints
&os.LinkError{Op:"rename", Old:"/Users/t/pprof", New:"/Users/t/pprof2", Err:0x1}
giving details on the actual error, and not just its string representation.
Starting with Go 1.13, if you just want to check if the underlying error is of a specific type you can do:
err := os.Rename("C:/temp/inUse", "c:/temp/Renamed")
if err != nil && errors.Is(err, syscall.EEXIST) {
fmt.Println("File already exists")
...
}
You can read more about error handling in Go 1.13 on the official Golang blog.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With