我希望func OpenFile()读取gzip文件和bzip2文件。稍后我将添加其他类型。

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
  }
}

我在另一个函数A中调用OpenFile():
    in := OpenFile(p)

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

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

请注意,gzip.NewReader(file)和bzip2.NewReader(file)返回不同的接口(interface)。

gzip:func NewReader(r io.Reader)(* Reader,error)//阅读器具有func Close()

bzip2:func NewReader(r io.Reader)io.Reader//io.Reader没有func Close()

这就是我不能首先返回NewReader(file)的原因。

谢谢!

最佳答案

正如其他人提到的,您应该从函数中返回一个io.ReadCloser。由于bzip2.NewReader()的返回值不满足io.ReadCloser,因此您需要创建自己的类型。

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
    }
}

10-01 15:01