github.com/scottcagno/storage@v1.8.0/pkg/_junk/_binary/writer.go (about) 1 package binary 2 3 import ( 4 "encoding/binary" 5 "io" 6 "os" 7 ) 8 9 // Writer provides a write-only file descriptor 10 type Writer struct { 11 path string // path of the file that is currently open 12 fd *os.File // underlying file to write to 13 open bool // is the file open 14 } 15 16 // OpenWriter returns a *writer for the file at the provided path 17 func OpenWriter(path string) (*Writer, error) { 18 // open file at specified path 19 fd, err := os.OpenFile(path, os.O_WRONLY, 0666) 20 if err != nil { 21 return nil, err 22 } 23 // seek to the end of the current file to continue appending data 24 _, err = fd.Seek(0, io.SeekEnd) 25 if err != nil { 26 return nil, err 27 } 28 // return new writer 29 return &Writer{ 30 path: path, 31 fd: fd, 32 open: true, 33 }, nil 34 } 35 36 // EncodeEntry writes the provided entry to disk 37 func EncodeEntry(w io.WriteSeeker, e *Entry) (int64, error) { 38 // error check 39 if e == nil { 40 return -1, ErrBadEntry 41 } 42 // get the file pointer offset for the entry 43 offset, err := w.Seek(0, io.SeekCurrent) 44 if err != nil { 45 return -1, err 46 } 47 // make buffer 48 buf := make([]byte, 26) 49 // encode and write entry id 50 binary.PutVarint(buf[0:10], e.Id) 51 _, err = w.Write(buf[0:10]) 52 if err != nil { 53 return -1, err 54 } 55 // encode and write entry key length 56 binary.LittleEndian.PutUint64(buf[10:18], uint64(len(e.Key))) 57 _, err = w.Write(buf[10:18]) 58 if err != nil { 59 return -1, err 60 } 61 // encode and write entry value length 62 binary.LittleEndian.PutUint64(buf[18:26], uint64(len(e.Value))) 63 _, err = w.Write(buf[18:26]) 64 if err != nil { 65 return -1, err 66 } 67 // write entry key 68 _, err = w.Write(e.Key) 69 if err != nil { 70 return -1, err 71 } 72 // write entry value 73 _, err = w.Write(e.Value) 74 if err != nil { 75 return -1, err 76 } 77 return offset, nil 78 } 79 80 // WriteEntryIndex writes the provided entry index to disk 81 func (w *Writer) WriteEntryIndex(e *EntryIndex) (int64, error) { 82 // call encode entry 83 offset, err := EncodeEntryIndex(w.fd, e) 84 if err != nil { 85 return -1, err 86 } 87 // make sure we call sync!! 88 err = w.fd.Sync() 89 if err != nil { 90 return -1, err 91 } 92 return offset, err 93 } 94 95 // WriteEntry writes the provided entry to disk 96 func (w *Writer) WriteEntry(e *Entry) (int64, error) { 97 // call encode entry 98 offset, err := EncodeEntry(w.fd, e) 99 if err != nil { 100 return -1, err 101 } 102 // make sure we call sync!! 103 err = w.fd.Sync() 104 if err != nil { 105 return -1, err 106 } 107 return offset, err 108 } 109 110 // Offset returns the *Writer's current file pointer offset 111 func (w *Writer) Offset() (int64, error) { 112 // check to make sure file is not closed 113 if !w.open { 114 return -1, ErrFileClosed 115 } 116 // return current offset using seek 117 return w.fd.Seek(0, io.SeekCurrent) 118 } 119 120 // Close syncs and closes the *writer 121 func (w *Writer) Close() error { 122 // ensure file is not closed 123 if !w.open { 124 return ErrFileClosed 125 } 126 // flush any cached or buffered data to the drive 127 err := w.fd.Sync() 128 if err != nil { 129 return err 130 } 131 // close writer 132 err = w.fd.Close() 133 if err != nil { 134 return err 135 } 136 w.open = false 137 w.path = "" 138 return nil 139 }