2017-09-22 7 views
0

forループ内のファイルを開き、その繰り返しの最後に終了する場合は、Closeをすぐに呼び出すか、Deferをクロージャを使用してトリックする必要がありますか?ループのファイルを開いてコピーする

私は、一連のファイル名を、chan stringから読み込み、zipファイルにコピーするデータを持っています。これはすべてgo funcで処理されます。私forループ内

go func(fnames <-chan string, zipfilename string) { 
    f, _ := os.Create(zipfilename) // ignore error handling for this example 
    defer f.Close() 
    zf := zip.NewWriter(f) 
    defer zf.Close() 
    for fname := range fnames { 
     r, _ := os.Open(fname) 
     w, _ := zf.Create(r.Name()) 
     io.Copy(w, r) 
     w.Close() 
     r.Close() 
}(files, "some name.zip") 

、書くために、より慣用的な移動のようになります。

for fname := range fnames { 
    func(){ 
     r, _ := os.Open(fname) 
     defer r.Close() 
     w, _ := zf.Create(r.Name()) 
     defer w.Close() 
     io.Copy(w, r) 
    }() 
} 

または私はと書かれた私のコードを続行すべきか?

+1

私は、他のものより多かれ少なかれ慣れているとは思わないが、最初の方が簡単です。エラー値をチェックするのは慣習的です。そのコードを追加すると、2番目の方法が簡単になります。 –

答えて

2

エラーを確認する必要があります。私はこれが単なる例にすぎないことを知っていますが、この場合は重要です。 Close()を延期するだけであれば、延期中にエラーがあったかどうかを実際に確認することはできません。

あなたはすべてそのエラー処理を追加したら
func copyFileToZip(zf *zip.Writer, filename string) error { 
    r, err := os.Open(filename) 
    if err != nil { 
     return err 
    } 
    defer r.Close() 

    w, err := zf.Create(r.Name()) 
    if err != nil { 
     return err 
    } 
    defer w.Close() 

    _, err = io.Copy(w, r) 
    if err != nil { 
     return err 
    } 

    return w.Close() 
} 

、関数が名前の関数にするために十分な大きさである:私はこれを書くでしょう

方法は、ヘルパー関数を作成することです。また、ライターを閉じるときにエラーをチェックするという追加の利点もあります。リーダーのエラーをチェックすることは、データが書き込まれた場合には影響を及ぼさないため、不要です。

+0

'defer w.Close()'と 'return w.Close()'の両方でOKですか? – Schwern

+0

タイプによって異なります。ほとんどの型でCloseを複数回呼び出すことができます。私は(ソースを読んで)Closeを2回呼び出すことが有効なzip.Writerであることを知りました。 2回目にエラーが返されますが、それは延期中であるため、問題ではありません。 –

関連する問題