func (reader *Reader) SkipLines() (e error) {
	for i := 0; i < reader.Skip; i++ {
		_, e = reader.ReadLine()
		if nil != e {
			log.Print("dsv: ", e)
			return
		}
	}
	return
}
SkipLines skip parsing n lines from input file.
The n is defined in the attribute "Skip"
package dsv
import (
	"bufio"
	"log"
	"os"
	"strings"
	"github.com/shuLhan/share/lib/tabula"
)
const (
	DatasetModeROWS = "ROWS"
	DatasetModeCOLUMNS = "COLUMNS"
	DatasetModeMATRIX = "MATRIX"
)
type Reader struct {
	Config
	dataset interface{}
	Input string `json:"Input"`
	Skip int `json:"Skip"`
	TrimSpace bool `json:"TrimSpace"`
	Rejected string `json:"Rejected"`
	InputMetadata []Metadata `json:"InputMetadata"`
	MaxRows int `json:"MaxRows"`
	DatasetMode string `json:"DatasetMode"`
	fRead *os.File
	fReject *os.File
	bufRead *bufio.Reader
	bufReject *bufio.Writer
}
func NewReader(config string, dataset interface{}) (reader *Reader, e error) {
	reader = &Reader{
		Input:         "",
		Skip:          0,
		TrimSpace:     true,
		Rejected:      DefaultRejected,
		InputMetadata: nil,
		MaxRows:       DefaultMaxRows,
		DatasetMode:   DefDatasetMode,
		dataset:       dataset,
		fRead:         nil,
		fReject:       nil,
		bufRead:       nil,
		bufReject:     nil,
	}
	e = reader.Init(config, dataset)
	if e != nil {
		return nil, e
	}
	return
}
func (reader *Reader) Init(fcfg string, dataset interface{}) (e error) {
	if dataset == nil {
		dataset = reader.GetDataset()
		if dataset == nil {
			dataset = &tabula.Dataset{}
			reader.dataset = dataset
		}
	}
	fcfg = strings.TrimSpace(fcfg)
	if fcfg != "" {
		e = ConfigOpen(reader, fcfg)
		if e != nil {
			return e
		}
		e = tabula.ReadDatasetConfig(dataset, fcfg)
		if e != nil {
			return e
		}
	}
	reader.SetDefault()
	reader.SetDatasetMode(reader.GetDatasetMode())
	ds := dataset.(tabula.DatasetInterface)
	md := reader.GetInputMetadata()
	for i := range md {
		md[i].Init()
		if !md[i].GetSkip() {
			col := tabula.Column{
				Type:       md[i].GetType(),
				Name:       md[i].GetName(),
				ValueSpace: md[i].GetValueSpace(),
			}
			ds.PushColumn(col)
		}
	}
	reader.SetInput(ConfigCheckPath(reader, reader.GetInput()))
	reader.SetRejected(ConfigCheckPath(reader, reader.GetRejected()))
	e = reader.OpenRejected()
	if nil != e {
		return e
	}
	return reader.OpenInput()
}
func (reader *Reader) SetDefault() {
	if strings.TrimSpace(reader.Rejected) == "" {
		reader.Rejected = DefaultRejected
	}
	if reader.MaxRows == 0 {
		reader.MaxRows = DefaultMaxRows
	}
	if strings.TrimSpace(reader.DatasetMode) == "" {
		reader.DatasetMode = DefDatasetMode
	}
	if reader.dataset == nil {
		reader.dataset = &tabula.Dataset{}
	}
}
func (reader *Reader) CopyConfig(src *Reader) {
	reader.ConfigPath = src.GetConfigPath()
	reader.Input = src.GetInput()
	reader.Skip = src.GetSkip()
	reader.TrimSpace = src.IsTrimSpace()
	reader.Rejected = src.GetRejected()
	reader.MaxRows = src.GetMaxRows()
	reader.DatasetMode = src.GetDatasetMode()
}
func (reader *Reader) GetInput() string {
	return reader.Input
}
func (reader *Reader) SetInput(path string) {
	reader.Input = path
}
func (reader *Reader) GetSkip() int {
	return reader.Skip
}
func (reader *Reader) SetSkip(n int) {
	reader.Skip = n
}
func (reader *Reader) IsTrimSpace() bool {
	return reader.TrimSpace
}
func (reader *Reader) GetRejected() string {
	return reader.Rejected
}
func (reader *Reader) SetRejected(path string) {
	reader.Rejected = path
}
func (reader *Reader) AddInputMetadata(md *Metadata) {
	reader.InputMetadata = append(reader.InputMetadata, *md)
	ds := reader.dataset.(tabula.DatasetInterface)
	ds.AddColumn(md.GetType(), md.GetName(), md.GetValueSpace())
}
func (reader *Reader) AppendMetadata(mdi MetadataInterface) {
	md := mdi.(*Metadata)
	reader.InputMetadata = append(reader.InputMetadata, *md)
}
func (reader *Reader) GetInputMetadata() []MetadataInterface {
	md := make([]MetadataInterface, len(reader.InputMetadata))
	for i := range reader.InputMetadata {
		md[i] = &reader.InputMetadata[i]
	}
	return md
}
func (reader *Reader) GetInputMetadataAt(idx int) MetadataInterface {
	return &reader.InputMetadata[idx]
}
func (reader *Reader) GetMaxRows() int {
	return reader.MaxRows
}
func (reader *Reader) SetMaxRows(max int) {
	reader.MaxRows = max
}
func (reader *Reader) GetDatasetMode() string {
	return reader.DatasetMode
}
func (reader *Reader) SetDatasetMode(mode string) {
	ds := reader.dataset.(tabula.DatasetInterface)
	switch strings.ToUpper(mode) {
	case DatasetModeROWS:
		ds.SetMode(tabula.DatasetModeRows)
	case DatasetModeCOLUMNS:
		ds.SetMode(tabula.DatasetModeColumns)
	case DatasetModeMATRIX:
		fallthrough
	default:
		ds.SetMode(tabula.DatasetModeMatrix)
		mode = DatasetModeMATRIX
	}
	reader.DatasetMode = mode
}
func (reader *Reader) GetNColumnIn() int {
	return len(reader.InputMetadata)
}
func (reader *Reader) OpenInput() (e error) {
	reader.fRead, e = os.OpenFile(reader.Input, os.O_RDONLY, 0600)
	if nil != e {
		return e
	}
	reader.bufRead = bufio.NewReader(reader.fRead)
	if reader.GetSkip() > 0 {
		e = reader.SkipLines()
		if nil != e {
			return
		}
	}
	return nil
}
func (reader *Reader) OpenRejected() (e error) {
	reader.fReject, e = os.OpenFile(reader.Rejected,
		os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	if nil != e {
		return e
	}
	reader.bufReject = bufio.NewWriter(reader.fReject)
	return nil
}
func (reader *Reader) Open() (e error) {
	e = reader.Close()
	if e != nil {
		return
	}
	e = reader.OpenInput()
	if e != nil {
		return
	}
	e = reader.OpenRejected()
	return
}