Ai
1 Star 1 Fork 0

bon-ami/eztools

Create your Gitee Account
Explore and code with more than 13.5 million developers,Free private repositories !:)
Sign up
文件
Clone or Download
cfg.go 7.66 KB
Copy Edit Raw Blame History
Allen Tse authored 2023-01-12 15:42 +08:00 . thorough comments and camel names
package eztools
import (
"encoding/csv"
"encoding/xml"
"io"
"os"
"path/filepath"
"github.com/shibukawa/configdir"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
func xmlPrepare(data interface{}, indent string) ([]byte, error) {
bytes, err := xml.MarshalIndent(data, "", indent)
if err != nil {
return nil, err
}
var PREFIX = []byte("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
return append(PREFIX, bytes...), nil
}
// XMLWrite writes file from input structure
// by a full path (with .xml extension)
// this reformats the file with indent provided
func XMLWrite(file string, data interface{}, indent string) error {
slc, err := xmlPrepare(data, indent)
if err != nil {
return err
}
return FileWrite(file, slc)
}
// XMLWriter writes with writer from input structure
// wrt is not Close()'d
func XMLWriter(wrt io.WriteCloser, data interface{}, indent string) error {
if wrt == nil {
return ErrOutOfBound
}
slc, err := xmlPrepare(data, indent)
if err != nil {
return err
}
_, err = wrt.Write(slc)
return err
}
// XMLWriteNoCreate writes existing file from input structure
// by a full path (with .xml extension)
// this reformats the file with indent provided
func XMLWriteNoCreate(file string, data interface{}, indent string) error {
slc, err := xmlPrepare(data, indent)
if err != nil {
return err
}
return FileWriteNoCreate(file, slc)
}
func fileRW1(dir, fn string, pathIn string, err error, fun func(string) error) (string, error) {
pathNew := filepath.Join(dir, fn+".xml")
ret := fun(pathNew)
if ret == nil {
return pathNew, nil
}
if len(pathIn) > 0 {
pathIn += ","
}
// TODO: return multiple errors from Go 1.20
return pathIn + pathNew, ret
}
// XMLWriteDefault writes file from input structure
// by a module name for both system config directory and file name
// home dir and current dir are also candidates in case of failure
// this reformats the file with indent provided
func XMLWriteDefault(module string, data interface{},
indent string) (pathFound string, err error) {
dirs := []string{GetCfgDir("", module)}
if home, err := os.UserHomeDir(); err == nil {
dirs = append(dirs, home)
}
dirs = append(dirs, ".")
fun := func(pathFound string) error {
return XMLWrite(pathFound, data, indent)
}
for _, dir1 := range dirs {
pathFound, err = fileRW1(dir1, module, pathFound, err, fun)
if err == nil {
return
}
}
return pathFound, ErrNoValidResults
}
// XMLRead reads file into input structure
// Return values from os.Stat(), os.ReadFile() and xml.Unmarshal()
func XMLRead(file string, data interface{}) error {
if _, err := os.Stat(file); err != nil {
return err
}
bytes, err := os.ReadFile(file)
if err != nil {
return err
}
return xml.Unmarshal(bytes, data)
}
// XMLReader reads with reader into input structure
// rdr is not Close()'d
func XMLReader(rdr io.ReadCloser, data interface{}) error {
bytes, err := io.ReadAll(rdr)
if err != nil {
return err
}
return xml.Unmarshal(bytes, data)
}
// GetCfgDir returns config directory by system
// Parameters: vendor can be empty
func GetCfgDir(vendor, module string) string {
dirs := configdir.New(vendor, module)
folders := dirs.QueryFolders(configdir.Global)
//folders[0].WriteFile("cfg.xml", nil)
return folders[0].Path
}
// XMLReadDefault reads config file into input structure from
// 1. givenpath,
// 2. or given file name (plus .xml) under one of these dirs,
// current dir, home dir, or system's config dir.
// the file name is taken as module name for system's config dir.
//
// Return values: full file name with path
//
// ErrNoValidResults=no file parsable
// other errors from XMLRead()
func XMLReadDefault(path, file string, cfg interface{}) (
pathFound string, err error) {
if len(path) > 0 {
err = XMLRead(path, cfg)
if err == nil {
return path, err
}
}
if len(file) < 1 {
return "", ErrInvalidInput
}
cfgPaths := []string{"."}
if home, err := os.UserHomeDir(); err == nil {
cfgPaths = append(cfgPaths, home)
}
cfgPaths = append(cfgPaths, GetCfgDir("", file))
fun := func(pathFound string) error {
return XMLRead(pathFound, cfg)
}
for _, dir1 := range cfgPaths {
pathFound, err = fileRW1(dir1, file, pathFound, err, fun)
if err == nil {
return
}
}
return pathFound, ErrNoValidResults
}
// Cfg defines the structure of a predefined config xml
type Cfg struct {
// Root of the XML
Root xml.Name `xml:"eztools"`
// Cmt = comments
Cmt string `xml:",comment"`
// Text is not used
Text string `xml:",chardata"`
// Db
Db CfgDb `xml:"db"`
// Map cfg of maps
Map []CfgMap `xml:"map"`
}
const (
// EncodingGbk gbk
EncodingGbk = "gbk"
)
var encodings = [...]struct {
str string
enc encoding.Encoding
}{
{EncodingGbk, simplifiedchinese.GBK},
}
// ListEnc list all valid encoding strings for
//
// CSVReadWtEnc()
// UTF-8 is default and not listed.
func ListEnc() (ret []string) {
for _, e := range encodings {
ret = append(ret, e.str)
}
return ret
}
type file2Writer func(f *os.File, encodingStr string) *transform.Writer
func csvWriteWtWriter(file string, data [][]string, f2w file2Writer,
encodingStr string, createIfNeeded bool) (err error) {
_, err = os.Stat(file)
var g int
g = os.O_WRONLY | os.O_TRUNC
if !createIfNeeded {
if err != nil {
return
}
} else {
g |= os.O_CREATE
}
f, err := os.OpenFile(file, g, FileCreatePermission)
if err != nil {
return
}
defer f.Close()
var wrt *csv.Writer
if f2w != nil {
wrt = csv.NewWriter(f2w(f, encodingStr))
} else {
wrt = csv.NewWriter(f)
}
return wrt.WriteAll(data)
}
// CSVWriteNoCreate writes data to existing file by a full path (with .csv extension)
func CSVWriteNoCreate(file string, data [][]string) error {
return csvWriteWtWriter(file, data, nil, "", false)
}
// CSVWrite writes UTF-8 file with slice of slice of string
func CSVWrite(file string, data [][]string) (err error) {
return csvWriteWtWriter(file, data, nil, "", true)
}
func csvWriterTransform(f *os.File, encodingStr string) *transform.Writer {
var encING encoding.Encoding
for _, v := range encodings {
if v.str == encodingStr {
encING = v.enc
break
}
}
return transform.NewWriter(f,
encoding.ReplaceUnsupported(encING.NewEncoder()))
}
// CSVWriteWtEnc writes file with slice of slice of string, with specified encoding
func CSVWriteWtEnc(file, encodingStr string, data [][]string) (err error) {
return csvWriteWtWriter(file, data,
csvWriterTransform, encodingStr, true)
}
// CSVWriteWtEncNoCreate writes existing file with slice of slice of string, with specified encoding
func CSVWriteWtEncNoCreate(file, encodingStr string, data [][]string) (err error) {
return csvWriteWtWriter(file, data,
csvWriterTransform, encodingStr, false)
}
type file2Reader func(*os.File) *transform.Reader
func csvReadWtReader(file string, f2r file2Reader) (ret [][]string, err error) {
if _, err = os.Stat(file); err != nil {
return
}
f, err := os.Open(file)
if err != nil {
return
}
defer f.Close()
var rdr *csv.Reader
if f2r != nil {
rdr = csv.NewReader(f2r(f))
} else {
rdr = csv.NewReader(f)
}
//rd := csv.NewReader(rdr)
return rdr.ReadAll()
}
// CSVRead reads UTF-8 file into slice of slice of string
func CSVRead(file string) (ret [][]string, err error) {
return csvReadWtReader(file, nil)
}
// CSVReadWtEnc reads file into slice of slice of string, with specified encoding
func CSVReadWtEnc(file, encodingStr string) (ret [][]string, err error) {
return csvReadWtReader(file,
func(f *os.File) *transform.Reader {
var encING encoding.Encoding
for _, v := range encodings {
if v.str == encodingStr {
encING = v.enc
break
}
}
return transform.NewReader(f,
/*encoding.ReplaceUnsupported*/ (encING.NewDecoder()))
})
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/bon-ami/eztools.git
git@gitee.com:bon-ami/eztools.git
bon-ami
eztools
eztools
v5.0.2

Search