2017-10-05 12 views
1

func OpenFile()에서 gzip 파일과 bzip2 파일을 읽길 원합니다. 나중에 다른 유형을 추가 할 것입니다.파일을 열고 다른 기능에서 NewReader를 만든 후 파일을 닫는 방법?

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

내 문제는 내가 사용하는 경우 "file.Close()를 연기"이다 OpenFile()에서 파일이 폐쇄 될 것이다 너무 일찍 그래서 나는 어떤 입력 값을 얻을 수 없습니다. A에서 파일을 닫으려면 어떻게해야합니까?

gzip.NewReader (file) 및 bzip2.NewReader (file)는 다른 인터페이스를 반환합니다.

GZIP : io.Reader // IO NewReader (R io.Reader) FUNC : NewReader (R io.Reader) (* 리더, 오류) FUNC // Reader가 FUNC 닫기()

의 bzip2 있습니다. 판독기에 func이 없습니다. Close()

이 때문에 NewReader (파일)를 처음으로 반환 할 수 없습니다.

감사합니다.

+1

관련/중복 가능성 (https://stackoverflow.com/questions/28279155/using-defer-with-pointers/28279237#28279237). – icza

답변

2

다른 언급했듯이 함수에서 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 
    } 
} 
+0

'gzip'과'file' 경우에'MyFileType'을 사용할 이유가 없습니다; 단지'gzip'과'file'을 직접 돌려 주면됩니다. – Flimzy

+1

참. 나는 그것을 고쳤다. –

4

bzip2.NewReader()io.ReadCloser을 반환하지 않으므로 Andy가 대답을 받아 들여야합니다.

그러나, 내 원래의 대답은 일반적인 경우 주소 :

당신은 io.Reader 대신 io.ReadCloser를 반환 할 수 있습니다 - 그런 식으로 그 함수의 소비자가 전화를 할 수 Close()

os.Fileos.Open()에 의해 반환 그래서 io.ReadCloser 충족 변경해야 할 것은 OpenFile() 함수의 서명 (반환 값)뿐입니다.

+0

답장을 보내 주셔서 감사합니다. 하지만 서명을 io.Reader에서 io.ReadCloser로 변경 한 후이 인수를 얻었습니다. bzip2 (type io.Reader)를 반환 인수의 type io.ReadCloser로 사용할 수 없습니다. io.Reader가 io.ReadCloser를 구현하지 않습니다 (Close 메서드가 없습니다.)) –

+0

나는 bzip2.NewReader()가'io를 반환하지 않았다.ReadCloser' - 버그처럼 보입니다.하지만 Andy의 대답은이 문제를 해결하는 가장 일반적인 방법입니다. –

3

io.ReadCloser를 반환하는 것은 관용적이며 이렇게하는 것이 좋습니다. 그것은 호출자에게 독자와 함께 작업 할 때 Close를 호출 할 것으로 예상된다는 것을 알려줍니다.

또 다른 옵션은 독자와 닫기 함수라는 두 개의 인수를 반환하는 것입니다. (당신이 어떤 래퍼 유형을 만들 필요가 없기 때문에)이 OpenFile 간단하게 만들 수 있습니다

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

,하지만 내 생각에 호출 측에 조금 서투른 : 그것은 context.WithDeadline 및 context.WithTimeout가하는 일입니다 .