2016-12-18 5 views
3

Goのio.Reader文書では、Read()が0以外の値nと、io.EOFを同時に返す可能性があります。残念なことに、FileRead()メソッドはそれを行いません。Goでio.ReaderでEOFをテストするにはどうすればよいですか?

EOFに達しても何バイトも読み込める場合、ファイルのReadメソッドは0以外の値を返しますnnilエラーです。ファイルの終わりにすでにnのゼロとエラーとしてio.EOFが返ってきたときにのみ読み込もうとします。

ファイルからデータを読み取ろうとせずにEOFに達したかどうかをテストする簡単な方法が見つかりませんでした。 0バイトのバッファを使ってRead()を実行すると、ファイルの最後にはゼロの戻り値nnilが返されます。

この最後の読み取りを避けるために、私が見つけた唯一の解決策は、ファイルに読み込む残りのバイト数を追跡​​することです。よりシンプルなソリューションはありますか?

+1

AFAIKではありません。シークや何かを使って現在のポジションを得ることができますが、それはより多くのシステムコールを必要とするので遅くなります。 –

+3

_always_がいくつかのバイトを読み込み、EOFを返す型を作るのはなぜですか? – JimB

+0

@JimBそれはすごいトリックです。私はその解決方法を採用します。しかし、先読みの代わりに、私はio.EOFをちょうど時間内に返すことができるように、読み込む残りのバイトを追跡します。私が最も好きなのは、自分のプログラムのどこにでもコードを変更する必要がないからです。私は、ファイルへのラッパーを提供する必要があります。 2つのオプションで素敵な答えを書いたら、私はそれをあなたに与えます。 – chmike

答えて

1

これまでに読み込んだバイト数を記録する新しいタイプを作成することができます。次に、EOFチェック時に、読み取られた予想バイト数と実際に読み取られたバイト数を比較できます。ここにサンプル実装があります。

:あなたはeofReaderに任意のリーダーをラップすることによって、このタイプを使用することができます

package main 

// ... imports 

// eofReader can be checked for EOF, without a Read. 
type eofReader struct { 
    r  io.Reader 
    count uint64 
} 

// AtEOF returns true, if the number of bytes read equals the file size. 
func (r *eofReader) AtEOF() (bool, error) { 
    f, ok := r.r.(*os.File) 
    if !ok { 
     return false, nil 
    } 
    fi, err := f.Stat() 
    if err != nil { 
     return false, err 
    } 
    return r.Count() == uint64(fi.Size()), nil 
} 

// Read reads and counts. 
func (r *eofReader) Read(buf []byte) (int, error) { 
    n, err := r.r.Read(buf) 
    atomic.AddUint64(&r.count, uint64(n)) 
    return n, err 
} 

// Count returns the count. 
func (r *eofReader) Count() uint64 { 
    return atomic.LoadUint64(&r.count) 
} 

eofReaderが読み込まれたバイト数を追跡​​した場合に、ファイルのサイズと比較する基本的なタイプはファイルであります

func main() { 
    f, err := os.Open("main.go") 
    if err != nil { 
     log.Fatal(err) 
    } 

    r := &eofReader{r: f} 
    log.Println(r.AtEOF()) 

    if _, err = ioutil.ReadAll(r); err != nil { 
     log.Fatal(err) 
    } 

    log.Println(r.AtEOF()) 
} 

// 2016/12/19 03:49:35 false <nil> 
// 2016/12/19 03:49:35 true <nil> 

コードgist

関連する問題