go-csv-table/gocsvtable.go
2025-03-30 15:29:43 -03:00

130 lines
2.6 KiB
Go

package gocsvtable
import (
"encoding/csv"
"fmt"
"io"
"os"
)
type GoCSVtable struct {
file *csv.Reader
rows int
data [][]string
headers map[string]int
Separator rune
Comment rune
lastRow int
// Row is the active CSV row, the data will start at 1
Row int
}
func (gct *GoCSVtable) OpenCSV(filename string) error {
osfile, err := os.Open(filename)
if err != nil {
return fmt.Errorf("Not possible to os.Open file: %s\n", err)
}
defer osfile.Close()
// The default rune is 0
if gct.Separator != 0 {
gct.file.Comma = gct.Separator
}
// The default rune is 0
if gct.Comment != 0 {
gct.file.Comment = gct.Comment
}
gct.file = csv.NewReader(osfile)
gct.data, err = gct.file.ReadAll()
if err != nil {
return fmt.Errorf("Not possible to csv.ReadAll file: %s\n", err)
}
gct.setHeaders()
// First data row is 1
gct.Row = 1
// Last row number
gct.lastRow = len(gct.data) - 1
return nil
}
// setHeaders will associate the headers names with the correct column number
func (gct *GoCSVtable) setHeaders() {
header := gct.data[0]
columnsNumber := len(header)
// Initiate Headers
gct.headers = make(map[string]int)
for field := 0; field < columnsNumber; field++ {
name := header[field]
gct.headers[name] = field
}
}
// GetHeader return the col number from a field string
func (gct *GoCSVtable) GetHeader(field string) (int, error) {
col, ok := gct.headers[field]
if !ok {
return 0, fmt.Errorf("Field '%s' does not exist", field)
}
return col, nil
}
// Next will jump to the next CSV row. If file is over, will return an io.EOF
func (gct *GoCSVtable) Next() error {
if gct.Row >= gct.lastRow {
return io.EOF
}
gct.Row++
return nil
}
// GetNumberOfRows will return the number of data rows, not considering the
// header
func (gct *GoCSVtable) GetNumberOfRows() int {
return gct.lastRow
}
// Read return a specific field from active row
func (gct *GoCSVtable) Read(field string) (string, error) {
col, err := gct.GetHeader(field)
if err != nil {
return "", err
}
return gct.data[gct.Row][col], nil
}
// Read and return the entire row
func (gct *GoCSVtable) ReadRow(row int) ([]string, error) {
if row > gct.lastRow {
return []string{}, fmt.Errorf("Not possible to read row %v. Data has max of %v rows.\n", row, gct.lastRow)
}
return gct.data[row], nil
}
// ReadCol will return a slice with all row values from a single column (field)
func (gct *GoCSVtable) ReadCol(field string) ([]string, error) {
data := []string{}
fieldNumber, err := gct.GetHeader(field)
if err != nil {
return data, err
}
for row := 1; row <= gct.lastRow; row++ {
data = append(data, gct.data[row][fieldNumber])
}
return data, nil
}