func (w *fileWriter) Close() (err error) {
	w.mu.RLock()
	err = w.fd.Close()
	w.mu.RUnlock()
	return
}
Close is an implementation of the io.WriteCloser interface.
package logger
import (
	"io"
	"os"
	"path/filepath"
	"sync"
	"sync/atomic"
	"time"
	"github.com/edoger/zkits-logger/internal"
)
func NewFileWriter(name string, max uint32) (io.WriteCloser, error) {
	if abs, err := filepath.Abs(name); err != nil {
		return nil, err
	} else {
		name = abs
	}
	if err := os.MkdirAll(filepath.Dir(name), 0766); err != nil {
		return nil, err
	}
	fd, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		return nil, err
	}
	i, err := fd.Stat()
	if err != nil {
		_ = fd.Close()
		return nil, err
	}
	return &fileWriter{name: name, max: max, size: uint32(i.Size()), fd: fd}, nil
}
func MustNewFileWriter(name string, max uint32) io.WriteCloser {
	w, err := NewFileWriter(name, max)
	if err != nil {
		panic(err)
	}
	return w
}
type fileWriter struct {
	name string
	mu   sync.RWMutex
	max  uint32
	size uint32
	fd   *os.File
}
func (w *fileWriter) Write(b []byte) (n int, err error) {
	w.mu.RLock()
	n, err = w.fd.Write(b)
	w.mu.RUnlock()
	if n > 0 && w.max != 0 && atomic.AddUint32(&w.size, uint32(n)) >= w.max {
		w.swap()
	}
	return
}
func (w *fileWriter) swap() {
	w.mu.Lock()
	defer w.mu.Unlock()
	if atomic.LoadUint32(&w.size) < w.max {
		return
	}
	if err := w.fd.Sync(); err != nil {
		internal.EchoError("Failed to sync log file %s: %s.", w.name, err)
		return
	}
	if err := w.fd.Close(); err != nil {
		if e, ok := err.(*os.PathError); !ok || e.Err != os.ErrClosed {
			internal.EchoError("Failed to close log file %s: %s.", w.name, err)
			return
		}
	}
	suffix := time.Now().Format("20060102150405")
	if err := os.Rename(w.name, w.name+"."+suffix); err != nil {
		internal.EchoError("Failed to rename log file %s to %s.%s: %s.", w.name, w.name, suffix, err)
		return
	}
	fd, err := os.OpenFile(w.name, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		internal.EchoError("Failed to open log file %s: %s.", w.name, err)
		return
	}
	w.fd = fd
	atomic.StoreUint32(&w.size, 0)
}