| // Copyright 2015 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Package bio implements common I/O abstractions used within the Go toolchain. | |
| package bio | |
| import ( | |
| "bufio" | |
| "io" | |
| "log" | |
| "os" | |
| ) | |
| // Reader implements a seekable buffered io.Reader. | |
| type Reader struct { | |
| f *os.File | |
| *bufio.Reader | |
| } | |
| // Writer implements a seekable buffered io.Writer. | |
| type Writer struct { | |
| f *os.File | |
| *bufio.Writer | |
| } | |
| // Create creates the file named name and returns a Writer | |
| // for that file. | |
| func Create(name string) (*Writer, error) { | |
| f, err := os.Create(name) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil | |
| } | |
| // Open returns a Reader for the file named name. | |
| func Open(name string) (*Reader, error) { | |
| f, err := os.Open(name) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return NewReader(f), nil | |
| } | |
| // NewReader returns a Reader from an open file. | |
| func NewReader(f *os.File) *Reader { | |
| return &Reader{f: f, Reader: bufio.NewReader(f)} | |
| } | |
| func (r *Reader) MustSeek(offset int64, whence int) int64 { | |
| if whence == 1 { | |
| offset -= int64(r.Buffered()) | |
| } | |
| off, err := r.f.Seek(offset, whence) | |
| if err != nil { | |
| log.Fatalf("seeking in output: %v", err) | |
| } | |
| r.Reset(r.f) | |
| return off | |
| } | |
| func (w *Writer) MustSeek(offset int64, whence int) int64 { | |
| if err := w.Flush(); err != nil { | |
| log.Fatalf("writing output: %v", err) | |
| } | |
| off, err := w.f.Seek(offset, whence) | |
| if err != nil { | |
| log.Fatalf("seeking in output: %v", err) | |
| } | |
| return off | |
| } | |
| func (r *Reader) Offset() int64 { | |
| off, err := r.f.Seek(0, 1) | |
| if err != nil { | |
| log.Fatalf("seeking in output [0, 1]: %v", err) | |
| } | |
| off -= int64(r.Buffered()) | |
| return off | |
| } | |
| func (w *Writer) Offset() int64 { | |
| if err := w.Flush(); err != nil { | |
| log.Fatalf("writing output: %v", err) | |
| } | |
| off, err := w.f.Seek(0, 1) | |
| if err != nil { | |
| log.Fatalf("seeking in output [0, 1]: %v", err) | |
| } | |
| return off | |
| } | |
| func (r *Reader) Close() error { | |
| return r.f.Close() | |
| } | |
| func (w *Writer) Close() error { | |
| err := w.Flush() | |
| err1 := w.f.Close() | |
| if err == nil { | |
| err = err1 | |
| } | |
| return err | |
| } | |
| func (r *Reader) File() *os.File { | |
| return r.f | |
| } | |
| func (w *Writer) File() *os.File { | |
| return w.f | |
| } | |
| // Slice reads the next length bytes of r into a slice. | |
| // | |
| // This slice may be backed by mmap'ed memory. Currently, this memory | |
| // will never be unmapped. The second result reports whether the | |
| // backing memory is read-only. | |
| func (r *Reader) Slice(length uint64) ([]byte, bool, error) { | |
| if length == 0 { | |
| return []byte{}, false, nil | |
| } | |
| data, ok := r.sliceOS(length) | |
| if ok { | |
| return data, true, nil | |
| } | |
| data = make([]byte, length) | |
| _, err := io.ReadFull(r, data) | |
| if err != nil { | |
| return nil, false, err | |
| } | |
| return data, false, nil | |
| } | |
| // SliceRO returns a slice containing the next length bytes of r | |
| // backed by a read-only mmap'd data. If the mmap cannot be | |
| // established (limit exceeded, region too small, etc) a nil slice | |
| // will be returned. If mmap succeeds, it will never be unmapped. | |
| func (r *Reader) SliceRO(length uint64) []byte { | |
| data, ok := r.sliceOS(length) | |
| if ok { | |
| return data | |
| } | |
| return nil | |
| } |