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  }