检查无效的文件描述符

时间:2019-10-11 20:49:25

标签: file go

有没有一种方法可以检查Go中文件描述符是否有效(在初始打开操作之后)?

考虑以下代码片段(如果在命令行标志中指定了打开调试文件的地方)

    upstreamDebug := flag.String("upstream_debug", "", "File for debugging")
    flag.Parse()

    var upstreamDebugFile os.File
    if *upstreamDebug != "" {
        upstreamDebugFile, err := os.OpenFile(*upstreamDebug, os.O_CREATE|os.O_WRONLY, 0644)
        if err != nil {
            log.Fatal(err)
        }
        log.Println("writing to", upstreamDebugFile.Name())
        defer upstreamDebugFile.Close()
    }

到目前为止,太好了。但是稍后,我们希望在&且仅当它是有效的描述符时才写到upstreamDebugFile-在if {..}子句之外。

是否有测试其有效性的方法? lib中似乎没有任何内置方法。与nil的比较

    if upstreamDebugFile == nil {

出现错误

cannot convert nil to type os.File

1 个答案:

答案 0 :(得分:1)

每条评论:

  

我将上游调试文件值用作io.WriteCloser。我发现即使未设置文件,它也不等于nil。

An io.WriteCloser is an instance of an interface。同时,os.OpenFile返回*os.File,即a pointer to a struct。该实现接口,但不是该接口类型的值。对于某些用途而言,这没什么大不了的,因为它实现接口这一事实意味着您可以将*os.File值存储在io.WriteCloser中。

但是,如以下程序所示,您必须谨慎测试io.WriteCloser是否为零,因为它通常不是:

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    var iface io.WriteCloser
    p, err := os.OpenFile("/bad/foo", os.O_CREATE, 0666)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("before assignment, iface = %#v, and iface == nil => %t\n", iface, iface == nil)
    iface = p
    fmt.Printf("after assignment, iface = %#v, and iface == nil => %t\n", iface, iface == nil)
    fmt.Printf("meanwhile p == nil => %t\n", p == nil)
}

Go Playground输出:

open /bad/foo: No such file or directory
before assignment, iface = <nil>, and iface == nil => true
after assignment, iface = (*os.File)(nil), and iface == nil => false
meanwhile p == nil => true

iface一旦分配了 type ,就不能对它进行整体测试。您必须像下面的程序中一样,开始测试其基础类型的实际值:

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    var iface io.WriteCloser
    p, err := os.OpenFile("/bad/foo", os.O_CREATE, 0666)
    if err != nil {
        fmt.Println(err)
    }
    iface = p
    fmt.Printf("iface.(*os.File) == nil => %t\n", iface.(*os.File) == nil)
}

Try it on the Go Playground.,但请注意,如果从未为iface分配类型为*os.File的值,则类型声明将失败!

如果要存储的内容始终是*os.File,只需声明变量为*os.File

var foo *os.File
if somecond {
    var err error
    foo, err = os.OpenFile(... arguments ...)
    ...
}
// later:
if foo != nil {
    ...
}

请注意,您也可以执行以下操作:

var iface io.WriteCloser
...
if somecond {
    p, err := os.OpenFile(...)
    ...
    if p != nil {
        iface = p
    }
}

,现在iface == nil就足够了。但是除非您真的打算使用多个不同的基础io.WriteCloser实现,否则请保持简单并直接使用*os.File