func (writer *Writer) WriteRawDataset(dataset tabula.DatasetInterface,
	sep *string,
) (
	int, error,
) {
	if nil == writer.fWriter {
		return 0, ErrNotOpen
	}
	if nil == dataset {
		return 0, nil
	}
	if sep == nil {
		sep = new(string)
		*sep = DefSeparator
	}
	var rows *tabula.Rows
	switch dataset.GetMode() {
	case tabula.DatasetModeColumns:
		cols := dataset.GetDataAsColumns()
		return writer.WriteRawColumns(cols, sep)
	case tabula.DatasetModeRows, tabula.DatasetModeMatrix:
		fallthrough
	default:
		rows = dataset.GetDataAsRows()
	}
	return writer.WriteRawRows(rows, sep)
}
WriteRawDataset will write content of dataset to file without metadata but
using separator `sep` for each record.

We use pointer in separator parameter, so we can use empty string as
separator.
package dsv
import (
	"bufio"
	"encoding/json"
	"log"
	"os"
	libbytes "github.com/shuLhan/share/lib/bytes"
	"github.com/shuLhan/share/lib/tabula"
)
const (
	DefSeparator = ","
	DefOutput = "output.dat"
	DefEscape = "\\"
)
type Writer struct {
	Config `json:"-"`
	Output string `json:"Output"`
	OutputMetadata []Metadata `json:"OutputMetadata"`
	fWriter *os.File
	BufWriter *bufio.Writer
}
func NewWriter(config string) (writer *Writer, e error) {
	writer = &Writer{
		Output:         "",
		OutputMetadata: nil,
		fWriter:        nil,
		BufWriter:      nil,
	}
	if config == "" {
		return
	}
	e = OpenWriter(writer, config)
	if e != nil {
		return nil, e
	}
	return
}
func (writer *Writer) GetOutput() string {
	return writer.Output
}
func (writer *Writer) SetOutput(path string) {
	writer.Output = path
}
func (writer *Writer) AddMetadata(md Metadata) {
	writer.OutputMetadata = append(writer.OutputMetadata, md)
}
func (writer *Writer) open(file string, flag int) (e error) {
	if file == "" {
		if writer.Output == "" {
			file = DefOutput
		} else {
			file = writer.Output
		}
	}
	writer.fWriter, e = os.OpenFile(file, flag, 0600)
	if nil != e {
		return e
	}
	writer.BufWriter = bufio.NewWriter(writer.fWriter)
	return nil
}
func (writer *Writer) OpenOutput(file string) (e error) {
	return writer.open(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY)
}
func (writer *Writer) ReopenOutput(file string) (e error) {
	if e = writer.Close(); e != nil {
		return
	}
	return writer.open(file, os.O_CREATE|os.O_APPEND|os.O_WRONLY)
}
func (writer *Writer) Flush() error {
	return writer.BufWriter.Flush()
}
func (writer *Writer) Close() (e error) {
	if nil != writer.BufWriter {
		e = writer.BufWriter.Flush()
		if e != nil {
			return
		}
	}
	if nil != writer.fWriter {
		e = writer.fWriter.Close()
	}
	return
}
func (writer *Writer) WriteRow(row *tabula.Row, recordMd []MetadataInterface) (
	e error,
) {
	nRecord := row.Len()
	v := []byte{}
	esc := []byte(DefEscape)
	for i := range writer.OutputMetadata {
		md := writer.OutputMetadata[i]
		rIdx, mdMatch := FindMetadata(&md, recordMd)
		if rIdx >= nRecord {
			continue
		}
		if mdMatch != nil && mdMatch.GetSkip() {
			continue
		}
		recV := (*row)[rIdx].Bytes()
		lq := md.GetLeftQuote()
		if lq != "" {
			v = append(v, []byte(lq)...)
		}
		rq := md.GetRightQuote()
		sep := md.GetSeparator()
		if md.T == tabula.TString {
			recV, _ = libbytes.EncloseToken(recV, esc, esc, nil)
		}
		if rq != "" && md.T == tabula.TString {
			recV, _ = libbytes.EncloseToken(recV, []byte(rq), esc, nil)
		} else if sep != "" && md.T == tabula.TString {
			recV, _ = libbytes.EncloseToken(recV, []byte(sep), esc, nil)
		}
		v = append(v, recV...)
		if rq != "" {
			v = append(v, []byte(rq)...)
		}
		if sep != "" {
			v = append(v, []byte(sep)...)
		}
	}
	v = append(v, DefEOL)
	_, e = writer.BufWriter.Write(v)
	return e
}
func (writer *Writer) WriteRows(rows tabula.Rows, recordMd []MetadataInterface) (
	n int,
	e error,
) {
	for n = range rows {
		e = writer.WriteRow(rows[n], recordMd)
		if nil != e {
			break
		}
	}
	_ = writer.Flush()
	return
}
func (writer *Writer) WriteColumns(columns tabula.Columns,
	colMd []MetadataInterface,
) (
	n int,
	e error,
) {
	nColumns := len(columns)
	if nColumns <= 0 {
		return
	}
	emptyRec := tabula.NewRecordString("")
	minlen, maxlen := columns.GetMinMaxLength()
	if colMd == nil {
		for _, col := range columns {
			md := &Metadata{
				Name: col.Name,
				T:    col.Type,
			}
			colMd = append(colMd, md)
		}
	}
	row := make(tabula.Row, nColumns)
	for ; n < minlen; n++ {
		for y, col := range columns {
			row[y] = col.Records[n]
		}
		e = writer.WriteRow(&row, colMd)
		if e != nil {
			goto err
		}
	}
	for ; n < maxlen; n++ {
		for y, col := range columns {
			if col.Len() > n {
				row[y] = col.Records[n]
			} else {
				row[y] = emptyRec
			}
		}
		e = writer.WriteRow(&row, colMd)
		if e != nil {
			goto err
		}
	}
err:
	_ = writer.Flush()
	return n, e
}
func (writer *Writer) WriteRawRow(row *tabula.Row, sep, esc []byte) (e error) {
	if sep == nil {
		sep = []byte(DefSeparator)
	}
	if esc == nil {
		esc = []byte(DefEscape)
	}
	v := []byte{}
	for x, rec := range *row {
		if x > 0 {
			v = append(v, sep...)
		}
		recV := rec.Bytes()
		if rec.Type() == tabula.TString {
			recV, _ = libbytes.EncloseToken(recV, sep, esc, nil)
		}
		v = append(v, recV...)
	}
	v = append(v, DefEOL)
	_, e = writer.BufWriter.Write(v)
	_ = writer.Flush()
	return e
}
func (writer *Writer) WriteRawRows(rows *tabula.Rows, sep *string) (
	nrow int,
	e error,
) {
	nrow = len(*rows)
	if nrow <= 0 {
		return
	}
	if sep == nil {
		sep = new(string)
		*sep = DefSeparator
	}
	escbytes := []byte(DefEscape)
	sepbytes := []byte(*sep)
	x := 0
	for ; x < nrow; x++ {
		e = writer.WriteRawRow((*rows)[x], sepbytes, escbytes)
		if nil != e {
			break
		}
	}
	return x, e
}
func (writer *Writer) WriteRawColumns(cols *tabula.Columns, sep *string) (
	nrow int,
	e error,
) {
	ncol := len(*cols)
	if ncol <= 0 {
		return
	}
	if sep == nil {
		sep = new(string)
		*sep = DefSeparator
	}
	minlen, maxlen := cols.GetMinMaxLength()
	esc := []byte(DefEscape)
	sepbytes := []byte(*sep)
	x := 0
	for ; x < minlen; x++ {
		v := cols.Join(x, sepbytes, esc)
		v = append(v, DefEOL)
		_, e = writer.BufWriter.Write(v)
		if nil != e {
			return x, e
		}
	}
	for ; x < maxlen; x++ {
		v := cols.Join(x, sepbytes, esc)
		v = append(v, DefEOL)
		_, e = writer.BufWriter.Write(v)
		if nil != e {
			break
		}
	}
	_ = writer.Flush()
	return x, e
}