github.com/pavlo67/common@v0.5.3/common/serialization/jlist.go (about) 1 package serialization 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "os" 8 "regexp" 9 10 "github.com/pavlo67/common/common/errors" 11 "github.com/pavlo67/common/common/filelib" 12 ) 13 14 const onJSONList = "on serialization.JSONList()" 15 16 func JSONList[T any](list []T, prefix, indent string) ([]byte, error) { 17 prefixBytes, indentBytes := []byte(prefix), []byte(indent) 18 19 jsonBytes := []byte{'[', '\n'} 20 21 for i, item := range list { 22 itemBytes, err := json.Marshal(item) 23 if err != nil { 24 return nil, errors.Wrap(err, onJSONList) 25 } 26 27 if i > 0 { 28 jsonBytes = append(append(jsonBytes, ','), prefixBytes...) 29 } 30 jsonBytes = append(append(jsonBytes, indentBytes...), itemBytes...) 31 } 32 33 return append(jsonBytes, '\n', ']'), nil 34 } 35 36 const onSavePart = "on serialization.SavePart()" 37 38 func SavePart(data interface{}, marshaler Marshaler, filename string) error { 39 40 logData, err := marshaler.Marshal(data) 41 if err != nil { 42 return errors.Wrap(err, onSavePart) 43 } else if err = filelib.AppendFile(filename, append(logData, '\n')); err != nil { 44 return errors.Wrap(err, onSavePart) 45 } 46 47 return nil 48 } 49 50 const onReadPart = "on serialization.ReadPart()" 51 52 func ReadPart(filename string, n int, marshaler Marshaler, data interface{}) error { 53 dataBytes, err := os.ReadFile(filename) 54 if err != nil { 55 return fmt.Errorf("reading %s got: %s / "+onReadPart, filename, err) 56 } 57 lines := bytes.Split(dataBytes, []byte{'\n'}) 58 if n < 0 || n >= len(lines) { 59 return fmt.Errorf("wrong n (%d) to get from %d lines / "+onReadPart, n, len(lines)) 60 } 61 62 if err := marshaler.Unmarshal(lines[n], data); err != nil { 63 return fmt.Errorf("unmarshaling %s got: %s / "+onReadPart, dataBytes, err) 64 } 65 66 return nil 67 } 68 69 var reEmptyLine = regexp.MustCompile(`^\s*$`) 70 71 const onReadAllPartsJSON = "on serialization.ReadAllPartsJSON()" 72 73 func ReadAllPartsJSON(filename string, data interface{}) error { 74 exists, isDir := filelib.FileExistsAny(filename) 75 if !exists { 76 return nil 77 } else if isDir { 78 return fmt.Errorf("%s is a directory / "+onReadAllPartsJSON, filename) 79 } 80 81 dataBytesRaw, err := os.ReadFile(filename) 82 if err != nil { 83 return fmt.Errorf("reading %s got: %s / "+onReadAllPartsJSON, filename, err) 84 } 85 var lines [][]byte 86 for _, line := range bytes.Split(dataBytesRaw, []byte{'\n'}) { 87 if !reEmptyLine.Match(line) { 88 lines = append(lines, line) 89 } 90 } 91 92 dataBytesLines := bytes.Join(lines, []byte{','}) 93 dataBytes := append([]byte{'['}, append(dataBytesLines, ']')...) 94 95 if err := json.Unmarshal(dataBytes, data); err != nil { 96 return fmt.Errorf("unmarshaling %s got: %s / "+onReadAllPartsJSON, dataBytes, err) 97 } 98 99 return nil 100 } 101 102 const onSaveAllPartsJSON = "on serialization.SaveAllPartsJSON()" 103 104 func SaveAllPartsJSON[T any](data []T, filename string) error { 105 var dataBytes []byte 106 107 for _, item := range data { 108 itemBytes, err := json.Marshal(item) 109 if err != nil { 110 return fmt.Errorf("marshaling %v got: %s / "+onSaveAllPartsJSON, item, err) 111 } 112 113 dataBytes = append(dataBytes, itemBytes...) 114 dataBytes = append(dataBytes, '\n') 115 } 116 117 err := os.WriteFile(filename, dataBytes, 0644) 118 if err != nil { 119 return errors.Wrap(err, onSaveAllPartsJSON) 120 } 121 122 return nil 123 }