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.getHeaders() // First data row is 1 gct.Row = 1 // Last row number gct.lastRow = len(gct.data) - 1 return nil } // getHeaders will associate the Headers names with the correct column number func (gct *GoCSVtable) getHeaders() { 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 } } // 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 { col := gct.Headers[field] return gct.data[gct.Row][col] } // 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 := gct.Headers[field] for row := 1; row <= gct.lastRow; row++ { data = append(data, gct.data[row][fieldNumber]) } return data, nil }