web-dev-qa-db-ja.com

Golangのバッファーリーダーから特定のバイト数を読み取る

bufioパッケージのgolangの特定の関数を知っています。

func (b *Reader) Peek(n int) ([]byte, error)

Peekは次のnバイトを返しますリーダーを進めずに。バイトは、次の読み取り呼び出しで有効でなくなります。 Peekがnバイト未満を返す場合、読み取りが短い理由を説明するエラーも返します。 nがbのバッファサイズより大きい場合、エラーはErrBufferFullです。

リーダーを進めるであるリーダーから特定のバイト数を読み取ることができる必要があります。基本的に、上記の機能と同じですが、それは読者を進歩させます。誰かがこれを達成する方法を知っていますか?

30
Kirk Backus

_bufio.Read_メソッドは、基になる_io.Read_を最大で1回呼び出すことに注意してください。つまり、EOFに到達せずにn < len(p)を返すことができます。正確にlen(p)バイトを読み取るか、エラーで失敗する場合は、次のように_io.ReadFull_を使用できます。

_n, err := io.ReadFull(reader, p)
_

これは、リーダーがバッファリングされている場合でも機能します。

67
monicuta
_func (b *Reader) Read(p []byte) (n int, err error)
_

http://golang.org/pkg/bufio/#Reader.Read

読み込まれるバイト数はlen(p)に制限されます

22
Chris

私はRead()を特に好みます。これは、任意のタイプのファイルを読み取る予定であり、データをチャンクで送信する場合にも役立ちます。以下は、その使用方法を示す例です。

fs, err := os.Open("fileName"); 

if err != nil{
    fmt.Println("error reading file")
    return
}

defer fs.Close()

reader := bufio.NewReader(fs)

buf := make([]byte, 1024)

for{
    v, _ := reader.Read(buf) //ReadString and ReadLine() also applicable or alternative

    if v == 0{
        return
    }
    //in case it is a string file, you could check its content here...
    fmt.Print(string(buf))
}
5

Nバイトサイズのバッファをリーダーに渡します。

3
zzzz

TLDR:

_my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
_

完全な答え:

@monicutaが_io.ReadFull_について言及しました。ここで私は別の方法を提供します。 _ioutil.ReadAll_と_io.LimitReader_を一緒にチェーンすることで機能します。最初にドキュメントを読んでみましょう:

_$ go doc ioutil.ReadAll
func ReadAll(r io.Reader) ([]byte, error)
     ReadAll reads from r until an error or EOF and returns the data it read. A
     successful call returns err == nil, not err == EOF. Because ReadAll is
     defined to read from src until EOF, it does not treat an EOF from Read as an
     error to be reported. 

$ go doc io.LimitReader
func LimitReader(r Reader, n int64) Reader
     LimitReader returns a Reader that reads from r but stops with EOF after n
     bytes. The underlying implementation is a *LimitedReader.
_

したがって、myReaderから42バイトを取得する場合は、次のようにします。

_import (
        "io"
        "io/ioutil"
)

func main() {
        // myReader := ...
        my42bytes, err := ioutil.ReadAll(io.LimitReader(myReader, 42))
        if err != nil {
                panic(err)
        }
        //...
}
_

これは、_io.ReadFull_と同等のコードです

_$ go doc io.ReadFull
func ReadFull(r Reader, buf []byte) (n int, err error)
    ReadFull reads exactly len(buf) bytes from r into buf. It returns the number
    of bytes copied and an error if fewer bytes were read. The error is EOF only
    if no bytes were read. If an EOF happens after reading some but not all the
    bytes, ReadFull returns ErrUnexpectedEOF. On return, n == len(buf) if and
    only if err == nil. If r returns an error having read at least len(buf)
    bytes, the error is dropped.
_
_import (
        "io"
)

func main() {
        // myReader := ...
        buf := make([]byte, 42)
        _, err := io.ReadFull(myReader, buf)
        if err != nil {
                panic(err)
        }
        //...
}
_

_io.ReadFull_と比較した場合の利点は、bufを手動で作成する必要がないことです。ここで、len(buf)は読み取るバイト数であり、読み取り時にbufを引数として渡します。

代わりに、_io.LimitReader_にmyReaderから最大42バイトが必要であることを伝え、_ioutil.ReadAll_を呼び出してすべてを読み取り、バイトのスライスとして結果を返します。成功した場合、返されるスライスは長さが42であることが保証されています。

3
navigaid

これを行うには、バイトスライスを作成し、 read でこのスライスにデータを作成する必要があります。

_n := 512
buff := make([]byte, n)
fs.Read(buff)  // fs is your reader. Can be like this fs, _ := os.Open('file')
_

func (b *Reader) Read(p []byte) (n int, err error)

Readはデータをpに読み込みます。 pに読み込まれたバイト数を返します。バイトは、基になるリーダーの最大1つの読み取りから取得されるため、nはlen(p)よりも小さい場合があります。

0
Salvador Dali