github.com/aldelo/common@v1.5.1/csv/csv.go (about) 1 package csv 2 3 /* 4 * Copyright 2020-2023 Aldelo, LP 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 import ( 20 "bufio" 21 "encoding/csv" 22 "errors" 23 "io" 24 "os" 25 ) 26 27 // Csv defines a struct for csv parsing and handling 28 type Csv struct { 29 f *os.File 30 r *bufio.Reader 31 cr *csv.Reader 32 ParsedCount int // data lines parsed count (data lines refers to lines below title columns) 33 TriedCount int // data lines tried count (data lines refers to lines below title columns) 34 } 35 36 // Open will open a csv file path for access 37 func (c *Csv) Open(path string) error { 38 if c == nil { 39 return errors.New("Open File Failed: " + "Csv Nil") 40 } 41 42 c.ParsedCount = -1 43 c.TriedCount = -1 44 45 var err error 46 47 // open file 48 c.f, err = os.Open(path) 49 50 if err != nil { 51 return errors.New("Open File Failed: " + err.Error()) 52 } 53 54 // open bufio reader 55 c.r = bufio.NewReader(c.f) 56 57 if c.r == nil { 58 return errors.New("Open Reader Failed: " + "Reader Nil") 59 } 60 61 return nil 62 } 63 64 // SkipHeaderRow will skip one header row, 65 // before calling csv parser loop, call this skip row to advance forward 66 func (c *Csv) SkipHeaderRow() error { 67 if c == nil { 68 return errors.New("Skip Header Row Failed: " + "Csv Nil") 69 } 70 71 if c.f == nil { 72 return errors.New("Skip Header Row Failed: " + "File Nil") 73 } 74 75 if c.r == nil { 76 return errors.New("Skip Header Row Failed: " + "Reader Nil") 77 } 78 79 _, _, err := c.r.ReadLine() 80 81 if err != nil { 82 return errors.New("Skip Header Row Failed: " + err.Error()) 83 } 84 85 return nil 86 } 87 88 // BeginCsvReader will start the csv parsing, 89 // this is called AFTER SkipHeaderRow is called, 90 // this sets the csv reader object and allows csv parsing access 91 func (c *Csv) BeginCsvReader() error { 92 if c == nil { 93 return errors.New("Begin Csv Reader Failed: " + "Csv Nil") 94 } 95 96 if c.f == nil { 97 return errors.New("Begin Csv Reader Failed: " + "File Nil") 98 } 99 100 if c.r == nil { 101 return errors.New("Begin Csv Reader Failed: " + "Reader Nil") 102 } 103 104 c.cr = csv.NewReader(c.r) 105 106 if c.cr == nil { 107 return errors.New("Begin Csv Reader Failed: " + "Csv Reader Nil") 108 } 109 110 return nil 111 } 112 113 // ReadCsv will read the current line of csv row, and return parsed csv elements, 114 // each time ReadCsv is called, the next row of csv is read 115 func (c *Csv) ReadCsv() (eof bool, record []string, err error) { 116 if c == nil { 117 return false, []string{}, errors.New("Read Csv Row Failed: " + "Csv Nil") 118 } 119 120 if c.cr == nil { 121 return false, []string{}, errors.New("Read Csv Row Failed: " + "Csv Reader Nil") 122 } 123 124 // read record of csv 125 record, err = c.cr.Read() 126 127 if err == io.EOF { 128 return true, []string{}, nil 129 } 130 131 // always increment tried count 132 c.TriedCount++ 133 134 if err != nil { 135 return false, []string{}, errors.New("Read Csv Row Failed: " + err.Error()) 136 } 137 138 if len(record) <= 0 { 139 return false, []string{}, nil 140 } 141 142 c.ParsedCount++ 143 144 return false, record, nil 145 } 146 147 // Close will close a csv file 148 func (c *Csv) Close() error { 149 if c == nil { 150 return nil 151 } 152 153 if c.f == nil { 154 return nil 155 } 156 157 c.r = nil 158 c.cr = nil 159 160 return c.f.Close() 161 }