Golang 표준 라 이브 러 리 Buffer

Buffer
   Go 표준 라 이브 러 리 Buffer 는 가 변 크기 의 바이트 버퍼 입 니 다. Wirte 와 Read 방법 으로 조작 할 수 있 습 니 다. Go 표준 라 이브 러 리 에서 Buffer 에 관 한 데이터 구 조 를 정의 합 니 다.
type Buffer struct {
    buf       []byte            // contents are the bytes buf[off : len(buf)]
    off       int               // read at &buf[off], write at &buf[len(buf)]
    runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
    bootstrap [64]byte          // memory to hold first slice; helps small buffers (Printf) avoid allocation.
    lastRead  readOp            // last read operation, so that Unread* can work correctly.
}
// The readOp constants describe the last action performed on
// the buffer, so that UnreadRune and UnreadByte can
// check for invalid usage.
type readOp int
const (
    opInvalid  readOp = iota // Non-read operation.
    opReadRune               // Read rune.
    opRead                   // Any other read operation.
)

   위 와 같이 Buffer 가 저장 한 데 이 터 는 off 에서 len (buf) 구역 사이 이 고 다른 구역 은 데이터 가 없 으 며 & buf [of] 부터 데 이 터 를 읽 고 & buf [len (buf)] 에서 데 이 터 를 쓸 수 밖 에 없습니다. 또한 메모리 에 대한 여러 번 의 조작 을 피하 기 위해 작은 버퍼 에 대해 Buffer 는 boottstrap 을 정의 하여 여러 번 의 메모리 조작 을 피 할 수 있 습 니 다. runeBytes 의 정의 도 마찬가지 입 니 다.Buffer 에 대한 조작 식별 자 lastRead 도 있 습 니 다.
Buffer 의 흔 한 조작
  • Buffer
    func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
    func NewBufferString(s string) *Buffer {
        return &Buffer{buf: []byte(s)}
    }
    초기 화 방법 뉴 버 퍼 는 buf 를 매개 변수 로 Buffer 를 초기 화 합 니 다. Buffer 는 읽 을 수도 있 고 쓸 수도 있 습 니 다. Buffer 를 읽 을 때 buf 는 일정한 데 이 터 를 채 워 야 합 니 다. 쓰 려 면 buf 는 일정한 용량 (capacity) 이 있어 야 합 니 다. 물론 new (Buffer) 를 통 해 Buffer 를 초기 화 할 수도 있 습 니 다.또 다른 방법 뉴 버 프 스 트 링 은 읽 을 수 있 는 버 프 를 하나의 string 으로 초기 화하 고 string 의 내용 으로 버 프 를 채 웁 니 다.
  • 읽 기와 쓰기 동작
    func (b *Buffer) Read(p []byte) (n int, err error)
    func (b *Buffer) Next(n int) []byte
    func (b *Buffer) ReadByte() (c byte, err error)
    func (b *Buffer) ReadRune() (r rune, size int, err error)
    func (b *Buffer) ReadBytes(delim byte) (line []byte, err error)
    func (b *Buffer) readSlice(delim byte) (line []byte, err error)
    func (b *Buffer) ReadString(delim byte) (line string, err error)
    func (b *Buffer) Write(p []byte) (n int, err error)
    func (b *Buffer) WriteString(s string) (n int, err error)
    func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error)
    func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)
    func (b *Buffer) WriteByte(c byte) error
    func (b *Buffer) WriteRune(r rune) (n int, err error)
    다음은 Read, ReadRune, ReadBytes 방법 을 분석 하고 방법 Read 에 대해 주로 세 가지 절 차 를 한다. 첫째, Buffer 가 비어 있 는 지 판단 하고 만약 에 Buffer 를 리 셋 한다.둘째, Buffer 의 buf 데 이 터 를 p 로 복사 하고 off 의 위치 표지 Buffer 의 읽 을 수 있 는 위 치 를 조정 합 니 다.셋째, 읽 기 식별 자 를 opRead 로 설정 합 니 다.
    func (b *Buffer) Read(p []byte) (n int, err error) {
        b.lastRead = opInvalid
        if b.off >= len(b.buf) {
            // Buffer is empty, reset to recover space.
            b.Truncate(0)
            if len(p) == 0 {
                return
            }
            return 0, io.EOF
        }
        n = copy(p, b.buf[b.off:])
        b.off += n
        if n > 0 {
            b.lastRead = opRead
        }
        return
    }

  •    방법 ReadRune () 은 Buffer 에서 UTF 8 인 코딩 된 rune 데 이 터 를 읽 는 방법 을 정의 합 니 다. 마찬가지 로 세 가지 절차 가 필요 합 니 다. 첫째, Buffer 가 비어 있 는 지 판단 합 니 다. 만약 에 Buffer 를 리 셋 합 니 다.둘째, 읽 기 조작 자 를 opReadRune 으로 설정 합 니 다.셋째, 읽 을 수 있 는 위치 오 프 의 byte 가 utf 8. Runeself 보다 작 는 지 판단 합 니 다. 만약 에 오 프 의 위 치 를 조정 하고 돌아 갑 니 다.그렇지 않 으 면 Buffer 의 데 이 터 를 rune 으로 디 코딩 하여 off 위 치 를 조정 하고 디 코딩 후의 rune 과 크기 를 되 돌려 줍 니 다.
    // ReadRune reads and returns the next UTF-8-encoded
    // Unicode code point from the buffer.
    // If no bytes are available, the error returned is io.EOF.
    // If the bytes are an erroneous UTF-8 encoding, it
    // consumes one byte and returns U+FFFD, 1.
    func (b *Buffer) ReadRune() (r rune, size int, err error) {
        b.lastRead = opInvalid
        if b.off >= len(b.buf) {
            // Buffer is empty, reset to recover space.
            b.Truncate(0)
            return 0, 0, io.EOF
        }
        b.lastRead = opReadRune
        c := b.buf[b.off]
        if c < utf8.RuneSelf {
            b.off++
            return rune(c), 1, nil
        }
        r, n := utf8.DecodeRune(b.buf[b.off:])
        b.off += n
        return r, n, nil
    }

     방법 ReadBytes (delim byte) 는 Buffer 에서 off 에서 첫 번 째 delim 사이 의 데 이 터 를 읽 고 delim, ReadBytes 를 포함 하여 개인 적 인 방법 readSlice 를 호출 하여 이 루어 집 니 다. readSlice 방법 은 delim 의 위 치 를 먼저 찾 고 존재 하지 않 으 면 off 에서 len (buf) 사이 의 데 이 터 를 되 돌려 줍 니 다. 존재 하면 off 에서 off + location (delim) + 1 사이 의 데 이 터 를 되 돌려 줍 니 다.그 중 하 나 는 delim 을 포함 하기 위해 서 이 며, 마지막 으로 조작 식별 자 를 opRead 로 설정 합 니 다.
    // ReadBytes reads until the first occurrence of delim in the input,
    // returning a slice containing the data up to and including the delimiter.
    // If ReadBytes encounters an error before finding a delimiter,
    // it returns the data read before the error and the error itself (often io.EOF).
    // ReadBytes returns err != nil if and only if the returned data does not end in
    // delim.
    func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
        slice, err := b.readSlice(delim)
        // return a copy of slice. The buffer's backing array may
        // be overwritten by later calls.
        line = append(line, slice...)
        return
    }
    // readSlice is like ReadBytes but returns a reference to internal buffer data.
    func (b *Buffer) readSlice(delim byte) (line []byte, err error) {
        i := IndexByte(b.buf[b.off:], delim)
        end := b.off + i + 1
        if i < 0 {
            end = len(b.buf)
            err = io.EOF
        }
        line = b.buf[b.off:end]
        b.off = end
        b.lastRead = opRead
        return line, err
    }

     마찬가지 로 해당 하 는 Write, Write Rune, ReadFrom, Write To 쓰기 방법 을 분석 하고 방법 Write, 상대 적 으로 Read 방법 에 있어 서 는 Buffer 공간 을 확장 한 다음 에 p 의 데 이 터 를 Buffer 로 복사 해 야 합 니 다.
    // Write appends the contents of p to the buffer, growing the buffer as
    // needed. The return value n is the length of p; err is always nil. If the
    // buffer becomes too large, Write will panic with ErrTooLarge.
    func (b *Buffer) Write(p []byte) (n int, err error) {
        b.lastRead = opInvalid
        m := b.grow(len(p))
        return copy(b.buf[m:], p), nil
    }

     방법 WriteRune 에 대해 서 는 먼저 쓸 데이터 rune 이 utf 8 보다 작 는 지 판단 합 니 다. RuneSelf 를 사용 하면 WriteByte 를 사용 하여 Buffer 에 기록 합 니 다. 그렇지 않 으 면 쓸 데이터 rune 을 utf 8 로 인 코딩 하고 Write 를 사용 하여 Buffer 에 기록 합 니 다.
    // WriteRune appends the UTF-8 encoding of Unicode code point r to the
    // buffer, returning its length and an error, which is always nil but is
    // included to match bufio.Writer's WriteRune. The buffer is grown as needed;
    // if it becomes too large, WriteRune will panic with ErrTooLarge.
    func (b *Buffer) WriteRune(r rune) (n int, err error) {
        if r < utf8.RuneSelf {
            b.WriteByte(byte(r))
            return 1, nil
        }
        n = utf8.EncodeRune(b.runeBytes[0:], r)
        b.Write(b.runeBytes[0:n])
        return n, nil
    }

    ReadFrom 방법 은 io. Reader 또는 io. Reader 인 터 페 이 스 를 실현 하 는 인 스 턴 스 에서 모든 데 이 터 를 Buffer 로 읽 습 니 다. 기본적으로 512 바이트 이상 을 읽 습 니 다. Buffer 공간 이 512 가 되 지 않 으 면 Buffer 공간 을 늘 려 야 합 니 다. 이 방법 은 읽 은 바이트 수 와 오류 정 보 를 되 돌려 줍 니 다.ReadFrom 에서 Buffer 가 비어 있 는 지 먼저 판단 하고 비어 있 으 면 Buffer 를 리 셋 합 니 다.그 다음으로 Buffer 의 free 공간 이 충분 한 지 판단 합 니 다. 512 보다 작고 of + free 가 512 보다 작 으 면 Buffer 가 0 에서 off 사이 의 공간 이 부족 하여 현재 Buffer 에서 읽 지 않 은 데이터 의 크기 를 저장 할 수 있 음 을 나타 냅 니 다. 이때 임시 버퍼 를 설정 하고 그 공간 Buffer 의 2 배 에 MinRead (512) 의 공간 을 더 하여 원래 Buffer 의 데 이 터 를 임시 버퍼 로 복사 합 니 다.그 다음 에 임시 버퍼 의 데 이 터 를 원본 Buffer 로 복사 하고 마지막 으로 io. Reader 의 Read 방법 으로 io. Reader 에서 데 이 터 를 읽 습 니 다. io. EOF 를 만 날 때 까지.
    // ReadFrom reads data from r until EOF and appends it to the buffer, growing
    // the buffer as needed. The return value n is the number of bytes read. Any
    // error except io.EOF encountered during the read is also returned. If the
    // buffer becomes too large, ReadFrom will panic with ErrTooLarge.
    func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
        b.lastRead = opInvalid
        // If buffer is empty, reset to recover space.
        if b.off >= len(b.buf) {
            b.Truncate(0)
        }
        for {
            if free := cap(b.buf) - len(b.buf); free < MinRead {
                // not enough space at end
                newBuf := b.buf
                if b.off+free < MinRead {
                    // not enough space using beginning of buffer;
                    // double buffer capacity
                    newBuf = makeSlice(2*cap(b.buf) + MinRead)
                }
                copy(newBuf, b.buf[b.off:])
                b.buf = newBuf[:len(b.buf)-b.off]
                b.off = 0
            }
            m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
            b.buf = b.buf[0 : len(b.buf)+m]
            n += int64(m)
            if e == io.EOF {
                break
            }
            if e != nil {
                return n, e
            }
        }
        return n, nil // err is EOF, so return nil explicitly
    }

     ReadFrom 방법 에 비해 WriteTo 방법 은 간단 합 니 다. WriteTo 는 Buffer 의 데 이 터 를 io. Writer 에 기록 하고 Buffer 에 데이터 가 없 을 때 까지 Buffer 가 비어 있 을 때 Buffer 를 리 셋 하고 되 돌려 줍 니 다.
    // WriteTo writes data to w until the buffer is drained or an error occurs.
    // The return value n is the number of bytes written; it always fits into an
    // int, but it is int64 to match the io.WriterTo interface. Any error
    // encountered during the write is also returned.
    func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
        b.lastRead = opInvalid
        if b.off < len(b.buf) {
            nBytes := b.Len()
            m, e := w.Write(b.buf[b.off:])
            if m > nBytes {
                panic("bytes.Buffer.WriteTo: invalid Write count")
            }
            b.off += m
            n = int64(m)
            if e != nil {
                return n, e
            }
            // all bytes should have been written, by definition of
            // Write method in io.Writer
            if m != nBytes {
                return n, io.ErrShortWrite
            }
        }
        // Buffer is now empty; reset.
        b.Truncate(0)
        return
    }

    3. 공간 확장 및 리 셋 
      Buffer 의 리 셋 방법 Reset () 은 Truncate (n int) 방법 을 호출 하여 Buffer 의 데 이 터 를 제거 합 니 다. Truncate 는 off 에서 시작 한 n 개의 읽 지 않 은 데 이 터 를 제외 한 모든 데 이 터 를 버 리 고 n 이 0 이면 Buffer 를 리 셋 합 니 다.
     
    // Truncate discards all but the first n unread bytes from the buffer.
    // It panics if n is negative or greater than the length of the buffer.
    func (b *Buffer) Truncate(n int) {
        b.lastRead = opInvalid
        switch {
        case n < 0 || n > b.Len():
            panic("bytes.Buffer: truncation out of range")
        case n == 0:
            // Reuse buffer space.
            b.off = 0
        }
        b.buf = b.buf[0 : b.off+n]
    }
    // Reset resets the buffer so it has no content.
    // b.Reset() is the same as b.Truncate(0).
    func (b *Buffer) Reset() { b.Truncate(0) }

     Buffer 에 데 이 터 를 쓸 때 모든 데 이 터 를 Buffer 에 쓸 수 있 도록 공간 을 확장 해 야 합 니 다. Buffer 는 Grow (n int) 방법 으로 Buffer 공간 을 확장 하 는 기능 을 실현 합 니 다. 이 방법 은 개인 적 인 방법 grow (n int) 를 호출 합 니 다.
     
    // grow grows the buffer to guarantee space for n more bytes.
    // It returns the index where bytes should be written.
    // If the buffer can't grow it will panic with ErrTooLarge.
    func (b *Buffer) grow(n int) int {
        m := b.Len()
        //   Buffer  ,  Buffer
        if m == 0 && b.off != 0 {
            b.Truncate(0)
        }
        //    n   Buffer   
        if len(b.buf)+n > cap(b.buf) {
            //      buf
            var buf []byte
            //Buffer buf     ,      ,  n  bootstrap   ,
            //   boostrap   buf            。
            if b.buf == nil && n <= len(b.bootstrap) {
                buf = b.bootstrap[0:]
            //       ,  b.buf            slice  ,   b.buf       buf。
            } else if m+n <= cap(b.buf)/2 {
                copy(b.buf[:], b.buf[b.off:])
                buf = b.buf[:m]
            } else {
                //    ,      
                buf = makeSlice(2*cap(b.buf) + n)
                copy(buf, b.buf[b.off:])
            }
            b.buf = buf
            b.off = 0
        }
        //  n   ,           
        b.buf = b.buf[0 : b.off+m+n]
        return b.off + m
    }
    // Grow grows the buffer's capacity, if necessary, to guarantee space for
    // another n bytes. After Grow(n), at least n bytes can be written to the
    // buffer without another allocation.
    // If n is negative, Grow will panic.
    // If the buffer can't grow it will panic with ErrTooLarge.
    func (b *Buffer) Grow(n int) {
        if n < 0 {
            panic("bytes.Buffer.Grow: negative count")
        }
        m := b.grow(n)
        b.buf = b.buf[0:m]
    }

    좋은 웹페이지 즐겨찾기