Golang中返回文件指针

neskvpey  于 2022-12-16  发布在  Go
关注(0)|答案(2)|浏览(254)

我还在努力学习Golang的基本知识。
请考虑以下示例代码:

func OpenOutputFile(name string) (fp *os.File) {
  fp, err := os.Create(name)
  if err != nil {
      panic(err)
  }

  defer func() {
      if err := fp.Close(); err != nil {
          panic(err)
      }
  }()

  return fp
}

我会假设调用:

fp := OpenOutputFile("output.txt")

现在我将fp设为文件指针(*os.File),这样我就可以调用如下语句:

io.WriteString(fp, "Hello World")

在另一个函数中。但调用此方法时,会生成错误:

0 write output.txt: bad file descriptor

所以返回的指针似乎是无效的。我怎样才能返回一个格式正确的指针来使用io.WriteString呢?
感谢你的帮助!
注意:当文件指针的创建和对文件指针的写入存在于同一个方法中时,一切都按预期执行。将逻辑分解为函数会导致它不按预期运行。

66bbxpm5

66bbxpm51#

The Go Programming Language Specification
延迟语句
一个“defer”语句调用的函数的执行被延迟到周围函数返回的时刻,要么是因为周围的函数执行了一个return语句,到达了函数体的末尾,要么是因为相应的goroutine出现了恐慌。
每次执行“defer”语句时,调用的函数值和参数都会像往常一样求值并重新保存,但实际函数不会被调用。相反,延迟函数会在周围函数返回之前立即被调用,顺序与它们被延迟的顺序相反。如果延迟函数值求值为nil,则在调用函数时执行会出现异常,而不是在执行“defer”语句时。
例如,如果延迟函数是一个函数文本,并且周围的函数具有在文本范围内的命名结果参数,则延迟函数可以在返回结果参数之前访问和修改这些参数。如果延迟函数具有任何返回值,则在函数完成时将丢弃这些值。

func OpenOutputFile(name string) (fp *os.File) {
    fp, err := os.Create(name)
    if err != nil {
        panic(err)
    }

    defer func() {
        if err := fp.Close(); err != nil {
            panic(err)
        }
    }()

    return fp
}

你打开文件

fp, err := os.Create(name)

你关闭文件

err := fp.Close()

Close之后,fp不再指向有效的文件描述符。

krugob8w

krugob8w2#

返回close函数并在更高的作用域中延迟它对我来说很有效,但我不知道这在Go语言中是否是一个好的实践,它依赖于原始函数之外的关闭/延迟:

func OpenFileFromArgs() (*os.File, func()) {
    if len(os.Args) < 2 {
        panic("input file not provided")
    }

    inputFilePath := os.Args[1]
    stat, err := os.Stat(inputFilePath)
    if err != nil {
        if errors.Is(err, os.ErrNotExist) {
            panic(fmt.Sprintf("file %s doens't exist", inputFilePath))
        } else {
            panic(fmt.Sprintf("error: %v", err))
        }
    }
    if stat.IsDir() {
        panic("provided path is a directory")
    }

    inputFile, err := os.Open(inputFilePath)
    closeFn := func() {
        err := inputFile.Close()
        if err != nil {
            panic("failed to close input file")
        }
    }

    return inputFile, closeFn

然后在更高的范围内:

inputFile, closeFn := library.OpenFileFromArgs()
    defer closeFn()

使用逐步调试器确认-在程序结束时,正确调用延迟关闭函数并关闭文件描述符。

相关问题