2016-04-27 171 views
4

我使用类似于下面几行的代码。如果目录被阻止,重命名可能会失败,因为某些应用程序中有一个文件已打开。检测重命名失败的原因

err := os.Rename("C:/temp/inUse", "c:/temp/Renamed") 

if err != nil { 
    fmt.Println(err) 
    ... 
} 

我能当我检查err这个内容来检测这样一个事实:

重命名C:/温度/ INUSE C:/温度/重命名:明镜Prozess卡恩nicht奥夫死 Datei zugreifen,da sie von einem anderen Prozess verwendet wird。

(这相当于“的方法是无法访问该文件,因为它是用来通过不同的处理”) 但是该消息取决于OS语言不同而不同。

是否有可能通过唯一的“错误代码”检测问题?我不介意该解决方案是否适用于Windows,并且不适用于Go支持的其他操作系统。

理想我可以做类似if err.Err == 32 { fmt.Println("Your directory is in use please ...

+1

我怀疑你可以从Go中的'err'中获得更多细节。但是,如果遇到这个问题,我会使用像perfmon这样的工具来找出什么是锁定文件,然后尝试在我的应用程序代码之外解决它 - 或者可能是代码更改 - 但是如果两个单独的应用程序共享文件您必须使用外部程序来协调它们,例如编写锁定文件。我粗略浏览了Go的'os'包,告诉我没有什么可以直接给你这个信息。 – evanmcdonnal

+0

@evanmcdonnal感谢您的输入。我知道如何使用sysinternals来找出哪个进程导致问题。我的目标是检测原因并向用户提示可能导致问题的提示 – Marged

+1

如果您有一些可以从命令行运行的东西,那么您可以使用Go的执行库(https://golang.org/pkg/os/ exec /)从您的应用程序中调用它,从std.out读取输出,解析锁定文件的其他应用程序的列表,然后将其显示给用户。 – evanmcdonnal

回答

3

通过os.Rename返回的错误是*os.LinkError类型,让你从操作系统访问底层错误的。你应该能够使用它来区分你遇到的特定错误。

您需要首先将错误转换为* os.LinkError。

例如,试图将一个文件夹(/Users/t/pprof)到另一个名称是写保护(/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) 
    } 
} 

提供以下的输出:

Op: %!(EXTRA string=rename) 
Old: %!(EXTRA string=/Users/t/pprof) 
New: %!(EXTRA string=/Users/t/pprof2) 
Err: %!(EXTRA syscall.Errno=operation not permitted) 

的操作系统错误代码可作为Err成员访问,但取决于您正在运行的操作系统会有所不同。

Err成员的类型为syscall.Errno。为了进一步检查实际的错误,你需要把它转换成该类型第一:

oserr := e.Err.(syscall.Errno) 

现在oserr可以在syscall包申报Errno的值进行比较。如果您在该页面上搜索ENOENT,则会找到它们。

例如,你可以通过做检查您的特定错误:

switch oserr { 
    case syscall.ENOENT: 
     // Handle this error 
    default: 
     // Handle other errors 
    } 
} 

一般情况下,这是非常方便的调试这些问题的排序时使用fmt.Printf。在上面的例子:

fmt.Println(err) 

打印

rename /Users/t/pprof /Users/t/pprof2: operation not permitted 

其中,作为

fmt.Printf("%#v\n", err) 

打印

&os.LinkError{Op:"rename", Old:"/Users/t/pprof", New:"/Users/t/pprof2", Err:0x1} 

实际误差透露更多细节,而不仅仅是它的字符串表示。

+0

谢谢,这些是我正在寻找的内幕。不幸的是,我不明白'testing.T'的来源。我怎么称呼这个? – Marged

+0

tests.T变量是go测试框架的一部分。这对编写像这样的测试用例的快速单元测试非常有用。您可以删除方法签名,并使用fmt.Printf替换t.Logf,以获得没有测试框架的类似功能。 –

+0

谢谢,但我只设法从'Err'中检索文本(这是特定于OS语言环境的文本),但未能获取基础值。在我的场景中(我已经用你的例子测试过),我检索&os.LinkError {操作:“重命名”,旧:“C:/ temp/inUse”,新建:“c:/ temp/Renamed”,Err:0x20} '但是当我访问'Err'时,我得到'0x20'的翻译结果。但我需要_raw_值。你有没有想法如何检索'0x20'而不需要在整个字符串上运行正则表达式? – Marged