代码之家  ›  专栏  ›  技术社区  ›  Zoe Sun

在打开文件并在另一个函数中创建新的读取器后,如何关闭文件?

  •  1
  • Zoe Sun  · 技术社区  · 7 年前

    func OpenFile(name string) io.Reader{
    
      file, err := os.Open(name)
    
      if err != nil {
       log.Fatal(err)
     }
    
      if(strings.Contains(name, ".gz")){
    
        gzip, gerr := gzip.NewReader(file)
        if gerr != nil {
            log.Fatal(gerr)
        }
        return gzip
    
      }else if(strings.Contains(name, ".bz2")){
    
        bzip2 := bzip2.NewReader(file)
        return bzip2    
    
      }else{
        return file     
      } 
    }
    

    我在另一个函数中调用OpenFile():

        in := OpenFile(p)
    
        for _, d := range fdb.Detect(in) {
            set[d] = true
            counter++
        }
        ...
    

    我的问题是,如果我在OpenFile()中使用“defer file.Close()”,文件将过早关闭,因此我无法获得任何输入值。如何在中关闭文件?

    注意gzip。NewReader(文件)和bzip2。NewReader(文件)返回不同的接口。

    gzip:func NewReader(r io.Reader)(*Reader,error)//读取器有一个func Close()

    bzip2:func NewReader(r io.Reader)io。读卡器//io。读卡器没有函数关闭()

    这就是我无法首先返回NewReader(文件)的原因。

    3 回复  |  直到 7 年前
        1
  •  4
  •   John Weldon user3678248    7 年前

    在这种情况下,因为 bzip2.NewReader() 不返回 io.ReadCloser 那么安迪的回答应该是可以接受的。

    然而,我最初的回答针对的是一般情况:

    你可能想回来 io。阅读关闭器 而不是 io.Reader -这样,该函数的使用者可以调用 Close()

    这个 os.File 返回人 os.Open() io。阅读关闭器 因此,唯一需要更改的是您的 OpenFile()

        2
  •  3
  •   Andy Schweig    7 年前

    正如其他人提到的,您应该返回 io.ReadCloser 从您的功能。自返回值 bzip2.NewReader() 不满足 io。阅读关闭器 ,您需要创建自己的类型。

    type myFileType struct {
        io.Reader
        io.Closer
    }
    
    func OpenFile(name string) io.ReadCloser {
    
        file, err := os.Open(name)
    
        if err != nil {
            log.Fatal(err)
        }
    
        if strings.Contains(name, ".gz") {
    
            gzip, gerr := gzip.NewReader(file)
            if gerr != nil {
                log.Fatal(gerr)
            }
            return gzip
    
        } else if strings.Contains(name, ".bz2") {
    
            bzip2 := bzip2.NewReader(file)
            return myFileType{bzip2, file}
    
        } else {
            return file
        }
    }
    
        3
  •  3
  •   Peter saif iqbal    7 年前

    返回io。ReadCloser是一种惯用方法,也是实现这一点的首选方法。它告诉调用者,当处理完读取器时,它将调用Close。

    另一个选项是返回两个参数,读取器和关闭函数。这就是语境。最后期限和背景。WithTimeout do:

    func OpenFile(name string) (r io.Reader, close func() error) {
        // ...
        var file *os.File
        gzip, _ := gzip.NewReader(file)
    
        return gzip, func() error { return file.Close() }
    }
    

    这可能会使OpenFile更简单(因为您不必创建任何包装类型),但在我看来,在调用方面有点笨拙。