1345 lines
33 KiB
Go
1345 lines
33 KiB
Go
/*
|
||
=================================================================================
|
||
* License: GPL-2.0 license
|
||
* Author: 众产® https://ciy.cn/code
|
||
* Version: 0.1.0
|
||
=================================================================================
|
||
命名规范。引入默认包
|
||
NewCiy* 类库实例
|
||
Ciy* 私有类库struct
|
||
Ciy*inf 接口定义
|
||
Ciy* 全局变量
|
||
CIY* 全局常量
|
||
=================================================================================
|
||
Log 日志全局变量
|
||
=================================================================================
|
||
|
||
* 功能函数相关
|
||
* Sleep 延时函数。秒为单位,支持0.5秒
|
||
* Pr 带时间的打印函数
|
||
* Iff 三元运算符
|
||
|
||
* Is_numeric 是否数字
|
||
* Is_int 是否整数
|
||
* Tostr 转字符串
|
||
* Toint 转int
|
||
* Tofloat 转float64
|
||
* Tobool 转bool
|
||
* Tostamp 转时间戳。将Y-m-d H:i:s格式转时间戳,同时识别字符串时间戳
|
||
* Todate 时间格式化。传递0为当前时间。支持Y-m-d H:i:s。支持1970以前
|
||
|
||
* Locinzone 当前经纬度是否在围栏中
|
||
* Timems 获取当前微秒数
|
||
* Ismobile 判断手机号是否合法
|
||
x Isweixin 判断客户端是否在微信中 post.go
|
||
* Idcard 判断身份证号合法
|
||
* Iduscc 判断统一社会信用代码合法
|
||
|
||
* 加解密相关
|
||
* CiySign 最多8位签名
|
||
* Encrypt 字符串加解密
|
||
* EnID/DeID ID数字加解密
|
||
* Conv33_10/Conv10_33 数字转33进制
|
||
* MD5/MD5Byte
|
||
|
||
* 字符串/数组相关
|
||
* Uniqid 生成唯一ID
|
||
* Array_unshift 数组顶部插入数据
|
||
* In_array 某元素在数组中存在位置
|
||
* Array_rand 随机抽取数组元素并删除
|
||
* Startwith/Endwith 首字符/尾字符匹配,可用strings.HasPrefix / strings.HasSuffix替代
|
||
|
||
* Strpos_first 字符数组优先匹配,一般匹配 ' "
|
||
* Gb_substr/Gb_strlen/Gb_haschinese 中文字符串处理函数
|
||
* Getstrparam/Setstrparam 比json还简化的数据保存方式,一般用于数据字典保存。例: name=AAA|age=12|cc=CCTT
|
||
|
||
* 数据库相关
|
||
* FieldAdd 手动增加列表显示字段,并返回排序字段字符串
|
||
* Getrelation 获取表内关联数据,用于大数据量表的所属ID转文字
|
||
* Tran_delcheck/Tran_delall/me 事务删除前确认/删除相关数据
|
||
* Getconfig/Setconfig 从配置表中读写配置项
|
||
|
||
* 字典相关
|
||
* Getcatas/Getsaascatas 从字典库/SaaS字典中读取 代码数组
|
||
* Id2map 将 id/name代码数组对 转换为 键值对
|
||
* Ccode 代码数组中,通过代码值找代码名
|
||
* Mcode 代码数组中,通过代码值找代码名,多级
|
||
* Scode 代码数组中,查找多个代码值,返回数组
|
||
* Dcode 代码数组中,通过代码名找代码值
|
||
|
||
* LOG相关
|
||
* SaveLog log信息记录到数据库log表
|
||
* SaveLogDB 增删改数据变更记录到数据库log表
|
||
x SaveLogFile 保存log信息写入到本地文件 log.go
|
||
|
||
* 文件相关
|
||
* DirMake/FileDel/Copy/Save/Load 目录创建,多级目录创建。默认权限666 创建多层新文件夹/文件静默删除/拷贝/保存/读取
|
||
* DirExist/FileExist 目录/文件是否存在
|
||
* Saaspath 获取SaaS多租户文件存储路径
|
||
* fileext 获取文件扩展名,如jpg
|
||
*/
|
||
|
||
package zciyon
|
||
|
||
import (
|
||
"bufio"
|
||
"bytes"
|
||
"crypto/hmac"
|
||
"crypto/md5"
|
||
"crypto/sha256"
|
||
"crypto/sha512"
|
||
"encoding/base64"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"io"
|
||
"math"
|
||
"math/rand"
|
||
"os"
|
||
"os/exec"
|
||
"regexp"
|
||
"strconv"
|
||
"strings"
|
||
"syscall"
|
||
"time"
|
||
"unicode"
|
||
)
|
||
|
||
const (
|
||
CIYRUN_DEV = 0
|
||
CIYRUN_PROD = 2
|
||
)
|
||
|
||
type Ciy_Vars struct {
|
||
Version string
|
||
Ini CiyINI
|
||
Func_succ int
|
||
Func_fail int
|
||
Func_commit int
|
||
Func_rollback int
|
||
Func_runms int
|
||
}
|
||
|
||
var Log *CiyLog //日志
|
||
var CiyVars *Ciy_Vars //应用全局变量
|
||
var CiyRunMode int //运行模式: 0 dev/1 test/2 prod
|
||
var CiyWebDir string //当前目录,尾缀不包含/
|
||
var CiyDirSep string //操作系统目录分隔符
|
||
var CiyDB *CiyMysql //单一数据库服务器或写库服务器连接池
|
||
var CiyRouteDB *CiyDBRoute //多台同一镜像读库服务器
|
||
// 对于单一数据库的多个微业务线,建议用map数据仓管理 如: c.DB["ag"].Get 或 CiyDBxxx
|
||
// 对于海量分库业务线,建议封装分布策略,聚合管理读写库
|
||
|
||
func init() {
|
||
CiyRunMode = CIYRUN_DEV
|
||
CiyVars = &Ciy_Vars{}
|
||
CiyVars.Version = ""
|
||
CiyVars.Func_succ = 0
|
||
CiyVars.Func_fail = 0
|
||
CiyVars.Func_commit = 0
|
||
CiyVars.Func_rollback = 0
|
||
CiyVars.Func_runms = 0
|
||
CiyDirSep = string(os.PathSeparator)
|
||
dir, err := os.Getwd()
|
||
if err == nil {
|
||
DirMake(dir + "/log")
|
||
DirMake(dir + "/web/ud/tmp")
|
||
CiyWebDir = strings.Replace(dir, CiyDirSep, "/", -1) + "/web"
|
||
}
|
||
}
|
||
func Sleep(s float64) {
|
||
if s < 1 {
|
||
time.Sleep(time.Duration(s*1000) * time.Millisecond)
|
||
} else {
|
||
if CiyRunMode == CIYRUN_DEV {
|
||
for i := 0; i < int(s); i++ {
|
||
time.Sleep(time.Duration(1000) * time.Millisecond)
|
||
}
|
||
} else {
|
||
time.Sleep(time.Duration(s*1000) * time.Millisecond)
|
||
}
|
||
}
|
||
}
|
||
func Clog(format any, args ...any) {
|
||
//https://github.com/go-ffmt/ffmt
|
||
now := time.Now()
|
||
millis := (now.UnixNano() / int64(time.Millisecond)) % 1000
|
||
fmt.Print(Todate(-1), ".", fmt.Sprintf("%03d", millis), ": ")
|
||
if fmstr, ok := format.(string); ok {
|
||
if strings.Contains(fmstr, "%") {
|
||
fmt.Printf(fmstr, args...)
|
||
fmt.Println("")
|
||
return
|
||
}
|
||
}
|
||
args = Array_unshift(args, format)
|
||
fmt.Println(args...)
|
||
// for _, arg := range args {
|
||
// typ := fmt.Sprintf("%T", arg)
|
||
// if typ == "uint8" {
|
||
// typ = "byte"
|
||
// }
|
||
// fmt.Printf(typ + ": ")
|
||
// switch {
|
||
// case typ == "string":
|
||
// fmt.Println(arg)
|
||
// case typ == "byte":
|
||
// fmt.Println(arg, fmt.Sprintf("%c", arg))
|
||
// // case int, int64, int32, int16, int8, uint, uint64, uint32, uint16:
|
||
// // fmt.Println(arg)
|
||
// // case float32, float64:
|
||
// // fmt.Println("["+fmt.Sprintf("%T", arg)+"]:", arg, fmt.Sprintf("%f", arg))
|
||
// // case complex64, complex128:
|
||
// // fmt.Println("["+fmt.Sprintf("%T", arg)+"]:", arg)
|
||
// // case bool:
|
||
// // fmt.Println("[bool]:", arg)
|
||
// case strings.HasPrefix(typ, "[]"):
|
||
// printarr(reflect.ValueOf(arg), 1)
|
||
// case strings.HasPrefix(typ, "map"):
|
||
// printmap(reflect.ValueOf(arg), 1)
|
||
// default:
|
||
// fmt.Println(arg)
|
||
// }
|
||
// }
|
||
}
|
||
func Iff[T int | float32 | float64 | string](b bool, t, f T) T {
|
||
if b {
|
||
return t
|
||
}
|
||
return f
|
||
}
|
||
func Is_numeric(a any) bool {
|
||
switch v := a.(type) {
|
||
case float32, float64, int, uint, int64, int32, int16, int8, uint64, uint32, uint16, uint8:
|
||
return true
|
||
default:
|
||
floatRegex := regexp.MustCompile(`^[-+]?(\d+(\.\d*)?|\.\d+)$`)
|
||
return floatRegex.MatchString(Tostr(v))
|
||
}
|
||
}
|
||
func Is_int(a any) bool {
|
||
switch v := a.(type) {
|
||
case float32, float64, int, uint, int64, int32, int16, int8, uint64, uint32, uint16, uint8:
|
||
return true
|
||
default:
|
||
integerRegex := regexp.MustCompile(`^-?[0-9]+$`)
|
||
return integerRegex.MatchString(Tostr(v))
|
||
}
|
||
}
|
||
func Randstr(nun int, argletter ...string) string {
|
||
letter := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||
if len(argletter) > 0 {
|
||
letter = argletter[0]
|
||
}
|
||
b := make([]byte, 10) // 创建一个长度为10的字节切片
|
||
for i := range b {
|
||
b[i] = letter[rand.Intn(len(letter))] // 随机生成字符
|
||
}
|
||
return string(b)
|
||
}
|
||
func Tostr(dat any, argdef ...string) (ret string) {
|
||
ret = ""
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
Clog("Tostr panic:", r)
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
}()
|
||
switch v := dat.(type) {
|
||
case int:
|
||
return strconv.Itoa(v)
|
||
case uint:
|
||
return strconv.Itoa(int(v))
|
||
case int64:
|
||
return strconv.Itoa(int(v))
|
||
case int32:
|
||
return strconv.Itoa(int(v))
|
||
case int16:
|
||
return strconv.Itoa(int(v))
|
||
case int8:
|
||
return strconv.Itoa(int(v))
|
||
case uint64:
|
||
return strconv.Itoa(int(v))
|
||
case uint32:
|
||
return strconv.Itoa(int(v))
|
||
case uint16:
|
||
return strconv.Itoa(int(v))
|
||
case uint8:
|
||
return strconv.Itoa(int(v))
|
||
case []byte:
|
||
return string(v)
|
||
case string:
|
||
return v
|
||
case float32, float64:
|
||
s := fmt.Sprintf("%.4f", v)
|
||
s = strings.TrimRight(s, "0")
|
||
s = strings.TrimRight(s, ".")
|
||
return s
|
||
case bool:
|
||
if v {
|
||
return "true"
|
||
} else {
|
||
return "false"
|
||
}
|
||
default:
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
func Toint(dat any, argdef ...int) (ret int) {
|
||
ret = 0
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
Clog("Toint panic:", r)
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
}()
|
||
switch v := dat.(type) {
|
||
case int:
|
||
return v
|
||
case uint:
|
||
return int(v)
|
||
case int64:
|
||
return int(v)
|
||
case int32:
|
||
return int(v)
|
||
case int16:
|
||
return int(v)
|
||
case int8:
|
||
return int(v)
|
||
case uint64:
|
||
return int(v)
|
||
case uint32:
|
||
return int(v)
|
||
case uint16:
|
||
return int(v)
|
||
case uint8:
|
||
return int(v)
|
||
case float32:
|
||
return int(v)
|
||
case float64:
|
||
return int(v)
|
||
case []byte:
|
||
num, err := strconv.Atoi(strings.TrimSpace(string(v)))
|
||
if err == nil {
|
||
return num
|
||
} else {
|
||
num, err := strconv.ParseFloat(strings.TrimSpace(string(v)), 64)
|
||
if err == nil {
|
||
return int(num)
|
||
}
|
||
}
|
||
case string:
|
||
num, err := strconv.Atoi(strings.TrimSpace(v))
|
||
if err == nil {
|
||
return num
|
||
} else {
|
||
num, err := strconv.ParseFloat(strings.TrimSpace(v), 64)
|
||
if err == nil {
|
||
return int(num)
|
||
}
|
||
}
|
||
case bool:
|
||
if v {
|
||
return 1
|
||
} else {
|
||
return 0
|
||
}
|
||
default:
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
func Tofloat(dat any, argdef ...float64) (ret float64) {
|
||
ret = 0.0
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
Clog("Tofloat panic:", r)
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
}()
|
||
switch v := dat.(type) {
|
||
case float64:
|
||
return v
|
||
case int:
|
||
return float64(v)
|
||
case uint:
|
||
return float64(v)
|
||
case int64:
|
||
return float64(v)
|
||
case int32:
|
||
return float64(v)
|
||
case int16:
|
||
return float64(v)
|
||
case int8:
|
||
return float64(v)
|
||
case uint64:
|
||
return float64(v)
|
||
case uint32:
|
||
return float64(v)
|
||
case uint16:
|
||
return float64(v)
|
||
case uint8:
|
||
return float64(v)
|
||
case float32:
|
||
return float64(v)
|
||
case []byte:
|
||
num, err := strconv.ParseFloat(string(v), 64)
|
||
if err == nil {
|
||
return num
|
||
}
|
||
case string:
|
||
num, err := strconv.ParseFloat(v, 64)
|
||
if err == nil {
|
||
return num
|
||
}
|
||
case bool:
|
||
if v {
|
||
return 1.0
|
||
} else {
|
||
return 0.0
|
||
}
|
||
default:
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
func Tobool(dat any, argdef ...bool) (ret bool) {
|
||
ret = false
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
Clog("Tobool panic:", r)
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
}()
|
||
switch v := dat.(type) {
|
||
case int, uint, uint64, uint32, uint16, uint8, int64, int32, int16, int8:
|
||
return v != 0
|
||
case float32:
|
||
return v > 0.0
|
||
case float64:
|
||
return v > 0.0
|
||
case []byte:
|
||
str := strings.TrimSpace(strings.ToLower(string(v)))
|
||
return str == "true" || str != "0"
|
||
case string:
|
||
str := strings.TrimSpace(strings.ToLower(v))
|
||
return str == "true" || str != "0"
|
||
case bool:
|
||
return v
|
||
default:
|
||
if len(argdef) > 0 {
|
||
ret = argdef[0]
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
func Tostamp(argstr ...string) int {
|
||
str := "now"
|
||
if len(argstr) > 0 {
|
||
str = argstr[0]
|
||
}
|
||
if str == "now" {
|
||
timestamp := time.Now().Unix()
|
||
return int(timestamp)
|
||
}
|
||
str = strings.Replace(str, "/", "-", -1)
|
||
if strings.Contains(str, "-") {
|
||
var ind, year, hour, minute, second int
|
||
var month, day = 1, 1
|
||
cnt := strings.Count(str, "-")
|
||
if cnt >= 2 {
|
||
ind = strings.Index(str, "-")
|
||
if ind > -1 {
|
||
year = Toint(str[:ind])
|
||
str = strings.TrimSpace(str[ind+1:])
|
||
}
|
||
} else {
|
||
//判读是否4位
|
||
ind = strings.Index(str, "-")
|
||
if ind > 3 {
|
||
year = Toint(str[:ind])
|
||
str = strings.TrimSpace(str[ind+1:])
|
||
} else {
|
||
year = time.Now().Year()
|
||
}
|
||
}
|
||
ind = strings.Index(str, "-")
|
||
if ind == -1 {
|
||
month = Toint(str)
|
||
} else {
|
||
month = Toint(str[:ind])
|
||
str = strings.TrimSpace(str[ind+1:])
|
||
ind = strings.Index(str, " ")
|
||
if ind == -1 {
|
||
day = Toint(str)
|
||
} else {
|
||
day = Toint(str[:ind])
|
||
str = strings.TrimSpace(str[ind+1:])
|
||
ind = strings.Index(str, ":")
|
||
if ind == -1 {
|
||
hour = Toint(str)
|
||
} else {
|
||
hour = Toint(str[:ind])
|
||
str = strings.TrimSpace(str[ind+1:])
|
||
ind = strings.Index(str, ":")
|
||
if ind == -1 {
|
||
minute = Toint(str)
|
||
} else {
|
||
minute = Toint(str[:ind])
|
||
str = strings.TrimSpace(str[ind+1:])
|
||
second = Toint(str)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
t := time.Date(year, time.Month(month), day, hour, minute, second, 0, time.Local)
|
||
timestamp := t.Unix()
|
||
return int(timestamp)
|
||
}
|
||
return 0
|
||
}
|
||
func Todate(tim int, format ...string) string {
|
||
var t time.Time
|
||
if tim == -1 {
|
||
t = time.Now()
|
||
} else if tim == 0 {
|
||
return ""
|
||
} else {
|
||
t = time.Unix(int64(tim), 0)
|
||
}
|
||
str := "Y-m-d H:i:s"
|
||
if len(format) > 0 {
|
||
str = format[0]
|
||
}
|
||
str = strings.Replace(str, "Y", fmt.Sprintf("%04d", t.Year()), -1)
|
||
str = strings.Replace(str, "y", fmt.Sprintf("%02d", t.Year()%100), -1)
|
||
str = strings.Replace(str, "m", fmt.Sprintf("%02d", t.Month()), -1)
|
||
str = strings.Replace(str, "d", fmt.Sprintf("%02d", t.Day()), -1)
|
||
str = strings.Replace(str, "H", fmt.Sprintf("%02d", t.Hour()), -1)
|
||
str = strings.Replace(str, "i", fmt.Sprintf("%02d", t.Minute()), -1)
|
||
str = strings.Replace(str, "s", fmt.Sprintf("%02d", t.Second()), -1)
|
||
return str
|
||
}
|
||
func Locinzone(paths string, zlat float64, zlng float64) bool {
|
||
//30.434272 120.274938,30.433977 120.277270,30.432403 120.277957,30.431764 120.276340,30.432270 120.273358,30.433997 120.273283
|
||
fences := strings.Split(paths, ",")
|
||
nvert := len(fences)
|
||
vertx := make([]float64, nvert)
|
||
verty := make([]float64, nvert)
|
||
for i, r := range fences {
|
||
latlng := strings.Split(r, " ")
|
||
vertx[i] = Tofloat(latlng[0])
|
||
verty[i] = Tofloat(latlng[1])
|
||
}
|
||
i, j := 0, nvert-1
|
||
c := false
|
||
for i < nvert {
|
||
if ((verty[i] > zlng) != (verty[j] > zlng)) &&
|
||
(zlat < (vertx[j]-vertx[i])*(zlng-verty[i])/(verty[j]-verty[i])+vertx[i]) {
|
||
c = !c
|
||
}
|
||
j = i
|
||
i++
|
||
}
|
||
return c
|
||
}
|
||
func RunCmd(name string, arg ...string) []string {
|
||
cmd := exec.Command(name, arg...)
|
||
var out bytes.Buffer
|
||
cmd.Stdout = &out
|
||
err := cmd.Run()
|
||
if err != nil {
|
||
fmt.Println("Error executing ps command:", err)
|
||
return make([]string, 0)
|
||
}
|
||
return strings.Split(out.String(), "\n")
|
||
}
|
||
func Timems() int {
|
||
return Toint(time.Now().UnixNano() / 1000000)
|
||
}
|
||
func Ismobile(mob string) bool {
|
||
match, _ := regexp.MatchString("^1\\d{10}$", mob)
|
||
return match
|
||
}
|
||
func Idcard(str string) (map[string]string, error) {
|
||
str = strings.ToLower(strings.TrimSpace(str))
|
||
if str == "" {
|
||
return nil, fmt.Errorf("身份证未输入")
|
||
}
|
||
if len(str) != 18 {
|
||
return nil, fmt.Errorf("身份证长度错误")
|
||
}
|
||
province := []string{"11", "12", "13", "14", "15", "21", "22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63", "64", "65", "71", "81", "82", "91"}
|
||
if !strings.Contains(strings.Join(province, ""), str[:2]) {
|
||
return nil, fmt.Errorf("身份证地区不合法")
|
||
}
|
||
birthyear := str[6:10]
|
||
birthmonth := str[10:12]
|
||
birthday := str[12:14]
|
||
birth := birthyear + "-" + birthmonth + "-" + birthday
|
||
stamp := Tostamp(birth)
|
||
if Todate(stamp, "Y-m-d") != birth {
|
||
return nil, fmt.Errorf("身份证生日错误")
|
||
}
|
||
if stamp > Tostamp() {
|
||
return nil, fmt.Errorf("身份证生日不能超过今天")
|
||
}
|
||
ahead17_char := str[:17]
|
||
last_char := str[17:]
|
||
factor := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||
c := []string{"1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2"}
|
||
t_res := 0
|
||
for i := 0; i < 17; i++ {
|
||
t_res += int(ahead17_char[i]) * factor[i]
|
||
}
|
||
calc_last_char := c[t_res%11]
|
||
if last_char != calc_last_char {
|
||
return nil, fmt.Errorf("身份证校验位错误")
|
||
}
|
||
sex := Toint(str[16:17])
|
||
if sex%2 == 0 {
|
||
sex = 2
|
||
} else {
|
||
sex = 1
|
||
}
|
||
return map[string]string{"code": str, "birth": birth, "sex": Tostr(sex), "area": str[:6]}, nil
|
||
}
|
||
func Iduscc(uscc string) (map[string]string, error) {
|
||
uscc = strings.ToUpper(strings.TrimSpace(uscc))
|
||
if uscc == "" {
|
||
return nil, fmt.Errorf("统一社会信用代码未输入")
|
||
}
|
||
if len(uscc) != 18 {
|
||
return nil, fmt.Errorf("统一社会信用代码不是18位")
|
||
}
|
||
province := []string{"11", "12", "13", "14", "15", "21", "22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42", "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63", "64", "65", "71", "81", "82", "91"}
|
||
if In_array(province, uscc[2:4]) == -1 {
|
||
return nil, fmt.Errorf("统一社会信用代码地区不合法")
|
||
}
|
||
lcrc := _tsucc(uscc[:17])
|
||
if Tostr(uscc[17]) != lcrc {
|
||
return nil, fmt.Errorf("统一社会信用代码校验位错误")
|
||
}
|
||
return map[string]string{"code": uscc, "area": uscc[2:8], "pn": uscc[:2]}, nil
|
||
}
|
||
func _tsucc(usc string) string {
|
||
list := map[string]int{"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "G": 16, "H": 17, "J": 18, "K": 19, "L": 20, "M": 21, "N": 22, "P": 23, "Q": 24, "R": 25, "T": 26, "U": 27, "W": 28, "X": 29, "Y": 30}
|
||
listf := map[int]string{}
|
||
for k, v := range list {
|
||
listf[v] = k
|
||
}
|
||
wi := []int{1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28}
|
||
num := 0
|
||
for i := 0; i < 17; i++ {
|
||
num += list[usc[i:i]] * wi[i]
|
||
}
|
||
result := 0
|
||
switch num % 31 {
|
||
case 0:
|
||
result = 0
|
||
default:
|
||
result = 31 - num%31
|
||
}
|
||
return listf[result]
|
||
}
|
||
|
||
func CiySign(str string, key string) string {
|
||
h := hmac.New(sha256.New, []byte(key))
|
||
h.Write([]byte(str))
|
||
signature := h.Sum(nil)
|
||
sid := fmt.Sprintf("%x", signature)
|
||
sid = sid[:16]
|
||
sid = strings.ReplaceAll(sid, "d", "p")
|
||
sid = strings.ReplaceAll(sid, "e", "z")
|
||
sid = strings.ReplaceAll(sid, "f", "m")
|
||
return sid
|
||
}
|
||
|
||
/* * *******************************************************************
|
||
* 函数名称:encrypt
|
||
* 函数作用:加密解密字符串
|
||
* 安全函数,建议有能力自行修改一些,源码不泄露,很难猜算法。
|
||
* 使用方法:
|
||
* 加密 :encrypt('str','E','nowamagic');
|
||
* 解密 :encrypt('被加密过的字符串','D','nowamagic');
|
||
* 参数说明:
|
||
* $string :需要加密解密的字符串
|
||
* $operation:判断是加密还是解密:E:加密 D:解密
|
||
* $key :加密的钥匙(密匙);
|
||
* ******************************************************************* */
|
||
// authstr := "加密字串"
|
||
// enstr := Encrypt(authstr, "E", p.Project_Commonkey)
|
||
// destr := Encrypt(enstr, "D", p.Project_Commonkey)
|
||
// Clog(authstr == destr, authstr, enstr, destr)
|
||
func Encrypt(str string, operation string, argkey ...string) string {
|
||
key := ""
|
||
if len(argkey) > 0 {
|
||
key = argkey[0]
|
||
}
|
||
keybyt := MD5Byte([]byte(key))
|
||
strbyt := []byte(str)
|
||
key_length := len(keybyt)
|
||
var byts []byte
|
||
if operation == "D" {
|
||
var err error
|
||
byts, err = base64.StdEncoding.DecodeString(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(str, "*", "="), "-", "+"), "_", "/")[1:])
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
} else {
|
||
mdbyt := MD5Byte(strbyt, keybyt)
|
||
var buffer2 bytes.Buffer
|
||
buffer2.Write(mdbyt[:8])
|
||
buffer2.Write(strbyt)
|
||
byts = buffer2.Bytes()
|
||
}
|
||
string_length := len(byts)
|
||
rndkey := make([]byte, 256)
|
||
box := make([]byte, 256)
|
||
result := make([]byte, 0)
|
||
for i := 0; i < 256; i++ {
|
||
rndkey[i] = keybyt[i%key_length]
|
||
box[i] = uint8(i)
|
||
}
|
||
for j, i := 0, 0; i < 256; i++ {
|
||
j = int(j+int(box[i])+int(rndkey[i])) % 256
|
||
tmp := box[i]
|
||
box[i] = box[j]
|
||
box[j] = tmp
|
||
}
|
||
for a, j, i := 0, 0, 0; i < string_length; i++ {
|
||
a = (a + 1) % 256
|
||
j = (j + int(box[a])) % 256
|
||
tmp := box[a]
|
||
box[a] = box[j]
|
||
box[j] = tmp
|
||
result = append(result, byts[i]^box[(int(box[a])+int(box[j]))%256])
|
||
}
|
||
if operation == "D" {
|
||
if bytes.Equal(result[:8], MD5Byte(result[8:], keybyt)[:8]) {
|
||
return string(result[8:])
|
||
} else {
|
||
return ""
|
||
}
|
||
} else {
|
||
return "1" + strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(base64.StdEncoding.EncodeToString(result), "=", "*"), "+", "-"), "/", "_")
|
||
}
|
||
}
|
||
|
||
/* * *******************************************************************
|
||
* 函数名称:enid/deid
|
||
* 函数作用:id加密函数/id解密函数。
|
||
* 安全函数,建议有能力自行修改一些
|
||
* 参数说明:
|
||
* $id 两位数的数字id(id>=10)
|
||
* 返回值:加密后的数字
|
||
* 例:enid(8245) = 872435
|
||
* 例:deid(872435) = 8245
|
||
* ******************************************************************* */
|
||
func EnID(id int, argkey ...int) string {
|
||
key := 253
|
||
if len(argkey) > 0 {
|
||
key = argkey[0]
|
||
}
|
||
strid := ""
|
||
if id <= 0 {
|
||
return "0"
|
||
}
|
||
if id < 10 {
|
||
strid = "0" + Tostr(id)
|
||
} else {
|
||
strid = Tostr(id)
|
||
}
|
||
fx := _calnumber(id, key)
|
||
ulen := len(strid)
|
||
return strid[:1] + fx[0:1] + strid[1:ulen-1] + fx[1:] + strid[len(strid)-1:]
|
||
}
|
||
func DeID(strid string, argkey ...int) int {
|
||
key := 253
|
||
if len(argkey) > 0 {
|
||
key = argkey[0]
|
||
}
|
||
ulen := len(strid)
|
||
fx := strid[1:2] + strid[ulen-2:ulen-1]
|
||
id := Toint(strid[:1] + strid[2:ulen-2] + strid[ulen-1:])
|
||
if fx == _calnumber(id, key) {
|
||
return id
|
||
}
|
||
return 0
|
||
}
|
||
|
||
/* * *******************************************************************
|
||
* 函数名称:calnumber
|
||
* 函数作用:换算id的加密校验数,被enid、deid函数调用。
|
||
* 参数说明:
|
||
* $key 默认加密因子,可以自行修改。尽量用奇数100-1000
|
||
* $len 返回校验数位数。
|
||
* 返回值:len位数字字符串
|
||
* 例:calnumber(8245,224,2) = 73
|
||
* ******************************************************************* */
|
||
func _calnumber(num, key int) string {
|
||
len := 2
|
||
if num > 250600 {
|
||
num %= 250600
|
||
}
|
||
n := num % 8566
|
||
if n < 100 {
|
||
n += 100
|
||
}
|
||
xx := num*n + key
|
||
if xx < 0 {
|
||
xx = -xx
|
||
}
|
||
if xx%13 > 8 {
|
||
xx += key
|
||
}
|
||
if xx%13 > 4 {
|
||
xx += key + key + key
|
||
}
|
||
ret := xx % Toint(math.Pow(10, Tofloat(len)))
|
||
if ret < 0 {
|
||
ret = -ret
|
||
}
|
||
return fmt.Sprintf("%0"+Tostr(len)+"d", ret)
|
||
}
|
||
func Conv33_10(num string) int {
|
||
n := 33
|
||
var new_num float64
|
||
new_num = 0.0
|
||
nNum := len(strings.Split(num, "")) - 1
|
||
for _, value := range strings.Split(num, "") {
|
||
tmp := -1
|
||
var nummap map[int]string = map[int]string{0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 7: "h", 8: "i", 9: "j", 10: "k", 11: "m", 12: "n", 13: "p", 14: "q", 15: "r", 16: "s", 17: "t", 18: "u", 19: "v", 20: "w", 21: "x", 22: "y", 23: "z", 24: "1", 25: "2", 26: "3", 27: "4", 28: "5", 29: "6", 30: "7", 31: "8", 32: "9"}
|
||
for k, v := range nummap {
|
||
if value == v {
|
||
tmp = k
|
||
}
|
||
}
|
||
if tmp != -1 {
|
||
new_num = new_num + float64(tmp)*math.Pow(float64(n), float64(nNum))
|
||
nNum = nNum - 1
|
||
} else {
|
||
break
|
||
}
|
||
}
|
||
return int(new_num)
|
||
}
|
||
func Conv10_33(num int) string {
|
||
var nummap map[int]string = map[int]string{0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", 7: "h", 8: "i", 9: "j", 10: "k", 11: "m", 12: "n", 13: "p", 14: "q", 15: "r", 16: "s", 17: "t", 18: "u", 19: "v", 20: "w", 21: "x", 22: "y", 23: "z", 24: "1", 25: "2", 26: "3", 27: "4", 28: "5", 29: "6", 30: "7", 31: "8", 32: "9"}
|
||
n := 33
|
||
new_num_str := ""
|
||
var remainder int
|
||
var remainder_string string
|
||
for num != 0 {
|
||
remainder = num % n
|
||
if 76 > remainder && remainder > 9 {
|
||
remainder_string = nummap[remainder]
|
||
} else {
|
||
remainder_string = strconv.Itoa(remainder)
|
||
}
|
||
new_num_str = remainder_string + new_num_str
|
||
num = num / n
|
||
}
|
||
return new_num_str
|
||
}
|
||
func MD5file(file string) string {
|
||
f, err := os.Open(file)
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
defer f.Close()
|
||
h := md5.New()
|
||
if _, err := io.Copy(h, f); err != nil {
|
||
return ""
|
||
}
|
||
return hex.EncodeToString(h.Sum(nil))
|
||
}
|
||
func MD5(src string) string {
|
||
h := md5.New()
|
||
h.Write([]byte(src))
|
||
return hex.EncodeToString(h.Sum(nil))
|
||
}
|
||
func MD5Byte(src ...[]byte) []byte {
|
||
h := md5.New()
|
||
for _, byt := range src {
|
||
h.Write(byt)
|
||
}
|
||
return h.Sum(nil)
|
||
}
|
||
func Sha256(src string) string {
|
||
hash := sha256.Sum256([]byte(src))
|
||
return hex.EncodeToString(hash[:])
|
||
}
|
||
func Sha512(src string) string {
|
||
hash := sha512.Sum512([]byte(src))
|
||
return hex.EncodeToString(hash[:])
|
||
}
|
||
func Uniqid(length int) string {
|
||
numbers := make([]byte, length)
|
||
for i := range numbers {
|
||
numbers[i] = byte(rand.Intn(256))
|
||
}
|
||
return fmt.Sprintf("%x", numbers)
|
||
}
|
||
func Array_unshift[T string | any](arr []T, value T, arginpoint ...int) []T {
|
||
if arr == nil {
|
||
return []T{value}
|
||
}
|
||
size := len(arr)
|
||
newArr := make([]T, size+1)
|
||
inpoint := 0
|
||
if len(arginpoint) > 0 {
|
||
inpoint = arginpoint[0]
|
||
}
|
||
for i := 0; i < inpoint; i++ {
|
||
newArr[i] = arr[i]
|
||
}
|
||
newArr[inpoint] = value
|
||
for i := inpoint; i < size; i++ {
|
||
newArr[i+1] = arr[i]
|
||
}
|
||
return newArr
|
||
}
|
||
func In_array[T string | int | float64](arr []T, val T) int {
|
||
for i, v := range arr {
|
||
if v == val {
|
||
return i
|
||
}
|
||
}
|
||
return -1
|
||
}
|
||
func Array_rand[T string | int | float64 | any](arr []T, num int) []T {
|
||
retarr := make([]T, num)
|
||
if len(arr) < num {
|
||
num = len(arr)
|
||
}
|
||
for i := 0; i < num; i++ {
|
||
ind := rand.Intn(len(arr))
|
||
retarr[i] = arr[ind]
|
||
arr = append(arr[:ind], arr[ind+1:]...)
|
||
}
|
||
return retarr
|
||
}
|
||
func Startwith(str string, suf string) bool {
|
||
return strings.HasPrefix(str, suf)
|
||
}
|
||
func Endwith(str string, suf string) bool {
|
||
return strings.HasSuffix(str, suf)
|
||
}
|
||
func Strpos_first(search string, offset int, findstrs ...string) (int, string, string) {
|
||
ind := strings.IndexAny(search[offset:], strings.Join(findstrs, ""))
|
||
if ind == -1 {
|
||
return -1, "", ""
|
||
}
|
||
ind += offset
|
||
f_str := search[ind : ind+1]
|
||
ind2 := strings.Index(search[ind+1:], f_str)
|
||
if ind2 > -1 {
|
||
ind2 += ind + 1
|
||
return ind, f_str, search[ind+1 : ind2]
|
||
}
|
||
return ind, f_str, ""
|
||
}
|
||
func Gb_substr(str string, length int, argdot ...string) string {
|
||
dot := ""
|
||
if len(argdot) > 0 {
|
||
dot = argdot[0]
|
||
}
|
||
ret := ""
|
||
for _, v := range str {
|
||
if unicode.Is(unicode.Han, v) {
|
||
length--
|
||
}
|
||
length--
|
||
ret += string(v)
|
||
if length <= 0 {
|
||
ret += dot
|
||
break
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
func Gb_strlen(str string) int {
|
||
count := 0
|
||
for _, v := range str {
|
||
if unicode.Is(unicode.Han, v) {
|
||
count++
|
||
}
|
||
count++
|
||
}
|
||
return count
|
||
}
|
||
func Gb_haschinese(str string) bool {
|
||
for _, v := range str {
|
||
if unicode.Is(unicode.Han, v) {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func Getstrparam(pstr string, argsplit ...string) map[string]string {
|
||
jsn := map[string]string{}
|
||
split := "|"
|
||
if len(argsplit) > 0 {
|
||
split = argsplit[0]
|
||
}
|
||
pstrs := strings.Split(pstr, split)
|
||
for _, str := range pstrs {
|
||
ind := strings.Index(str, "=")
|
||
if ind > 0 {
|
||
jsn[strings.TrimSpace(str[:ind])] = strings.TrimSpace(str[ind+1:])
|
||
} else {
|
||
jsn[strings.TrimSpace(str)] = ""
|
||
}
|
||
}
|
||
return jsn
|
||
}
|
||
func Setstrparam(parr map[string]string, argsplit ...string) string {
|
||
rets := make([]string, 0)
|
||
split := "|"
|
||
if len(argsplit) > 0 {
|
||
split = argsplit[0]
|
||
}
|
||
for k, v := range parr {
|
||
rets = append(rets, k+"="+v)
|
||
}
|
||
return strings.Join(rets, split)
|
||
}
|
||
func FieldAdd(field *map[string]map[string]any, fshow *string, inpoint int, fname string, comment string) {
|
||
(*field)[fname] = map[string]any{
|
||
"c": comment,
|
||
}
|
||
fshows := strings.Split(*fshow, ",")
|
||
if inpoint == -1 {
|
||
if len(fshows[0]) == 0 {
|
||
fshows[0] = fname
|
||
} else {
|
||
fshows = append(fshows, fname)
|
||
}
|
||
} else {
|
||
fshows = Array_unshift(fshows, fname, inpoint)
|
||
}
|
||
*fshow = strings.Join(fshows, ",")
|
||
}
|
||
|
||
// Getrelation(CiyDB, rows, "xx_user", "xxid", map[string]string{"column": "id,name"}, map[string]string{"queryid": "id"})
|
||
func Getrelation(db *CiyMysql, rows []map[string]any, table string, field string, argopn ...map[string]string) []map[string]any {
|
||
column := "id,name"
|
||
queryid := "id"
|
||
if len(argopn) > 0 {
|
||
for _, arg := range argopn {
|
||
if v, ok := arg["column"]; ok {
|
||
column = v
|
||
}
|
||
if v, ok := arg["queryid"]; ok {
|
||
queryid = v
|
||
}
|
||
}
|
||
}
|
||
ids := []string{}
|
||
for _, row := range rows {
|
||
ids = append(ids, Tostr(row[field]))
|
||
}
|
||
if len(ids) == 0 {
|
||
return []map[string]any{}
|
||
}
|
||
csql := NewCiySQL(table)
|
||
csql.Where(queryid+" in ", strings.Join(ids, ","))
|
||
csql.Column(column)
|
||
rows2, _, err := db.Get(csql)
|
||
if err != nil {
|
||
return []map[string]any{}
|
||
}
|
||
return rows2
|
||
}
|
||
func Delcheck(db *CiyMysql, delid int, table, field, msg string) {
|
||
csql := NewCiySQL(table)
|
||
csql.Where(field, delid)
|
||
cnt := Toint(db.Get1(csql))
|
||
if cnt > 0 {
|
||
panic(fmt.Sprintf("存在%d个%v,不能删除", cnt, msg))
|
||
}
|
||
}
|
||
func Delall(db *CiyMysql, delid int, table, field, msg string) {
|
||
csql := NewCiySQL(table)
|
||
csql.Where(field, delid)
|
||
_, err := db.Delete(csql)
|
||
if err != nil {
|
||
panic(msg + "删除失败:" + err.Error())
|
||
}
|
||
}
|
||
func Delme(db *CiyMysql, delid int, table string) {
|
||
csql := NewCiySQL(table)
|
||
csql.Where("id", delid)
|
||
_, err := db.Delete(csql)
|
||
if err != nil {
|
||
panic("删除失败:" + err.Error())
|
||
}
|
||
}
|
||
func Mapid2data(datas []map[string]any) map[int]map[string]any {
|
||
ret := map[int]map[string]any{}
|
||
for _, data := range datas {
|
||
ret[Toint(data["id"])] = data
|
||
}
|
||
return ret
|
||
}
|
||
func Ccode(rows []map[string]any, code int) string {
|
||
showcode := "id"
|
||
showtitle := "name"
|
||
for _, row := range rows {
|
||
if code == Toint(row[showcode]) {
|
||
return Tostr(row[showtitle])
|
||
}
|
||
}
|
||
return "--"
|
||
}
|
||
func Mcode(rows []map[string]any, code int) []string {
|
||
showcode := "id"
|
||
showtitle := "name"
|
||
upcode := "upid"
|
||
codes := make([]string, 0)
|
||
for i := 0; i < 10; i++ {
|
||
if code <= 0 {
|
||
break
|
||
}
|
||
bfind := false
|
||
for _, row := range rows {
|
||
if code == Toint(row[showcode]) {
|
||
codes = append(codes, Tostr(row[showtitle]))
|
||
code = Toint(row[upcode])
|
||
bfind = true
|
||
break
|
||
}
|
||
}
|
||
if !bfind {
|
||
break
|
||
}
|
||
}
|
||
lencode := len(codes)
|
||
ret := make([]string, lencode)
|
||
for i := 0; i < lencode; i++ {
|
||
ret[i] = codes[lencode-1-i]
|
||
}
|
||
return ret
|
||
}
|
||
|
||
func Scode(rows []map[string]any, code string) []string {
|
||
showcode := "id"
|
||
showtitle := "name"
|
||
rets := make([]string, 0)
|
||
codes := strings.Split(code, ",")
|
||
for _, c := range codes {
|
||
if c == "" {
|
||
continue
|
||
}
|
||
for _, row := range rows {
|
||
if c == row[showcode] {
|
||
rets = append(rets, Tostr(row[showtitle]))
|
||
break
|
||
}
|
||
}
|
||
}
|
||
return rets
|
||
}
|
||
|
||
func Dcode(rows []map[string]any, codename string) int {
|
||
showcode := "id"
|
||
showtitle := "name"
|
||
for _, row := range rows {
|
||
if codename == row[showtitle] {
|
||
return Toint(row[showcode])
|
||
}
|
||
}
|
||
return -1
|
||
}
|
||
func LogDBStr(oldrow map[string]any, newrow map[string]any) string {
|
||
msg := ""
|
||
if oldrow != nil && newrow != nil {
|
||
msg = "Upd=" + Tostr(oldrow["id"])
|
||
modify := false
|
||
for f, v := range newrow {
|
||
if _, ok := oldrow[f]; !ok {
|
||
continue
|
||
}
|
||
if oldrow[f] != v {
|
||
msg += "_|@|_" + f + "=" + Tostr(oldrow[f]) + "→" + Tostr(v)
|
||
modify = true
|
||
}
|
||
}
|
||
if !modify {
|
||
return ""
|
||
}
|
||
} else if newrow != nil {
|
||
msg = "Ins=" + Tostr(newrow["newid"])
|
||
for f, v := range newrow {
|
||
if f == "newid" || f == "id" {
|
||
continue
|
||
}
|
||
msg += "_|@|_" + f + "=" + Tostr(v)
|
||
}
|
||
} else if oldrow != nil {
|
||
msg = "Del=" + Tostr(oldrow["id"])
|
||
for f, v := range oldrow {
|
||
if f == "id" {
|
||
continue
|
||
}
|
||
msg += "_|@|_" + f + "=" + Tostr(v)
|
||
}
|
||
} else {
|
||
return ""
|
||
}
|
||
return msg
|
||
}
|
||
func DirMake(dir string, argpower ...int) error {
|
||
power := 0777
|
||
if len(argpower) > 0 {
|
||
power = argpower[0]
|
||
}
|
||
if dir == "" {
|
||
return fmt.Errorf("DirMake Error:dir is empty")
|
||
}
|
||
err := DirExist(dir)
|
||
if err == nil {
|
||
return nil
|
||
}
|
||
err = os.MkdirAll(dir, os.ModeDir)
|
||
if err != nil {
|
||
err = fmt.Errorf("dirMake Error:%v[%v]", err, dir)
|
||
Log.Error("DIR", err.Error())
|
||
return err
|
||
}
|
||
err = syscall.Chmod(dir, uint32(power))
|
||
if err != nil {
|
||
err = fmt.Errorf("dirMake setting permissions Error:%v[%v]", err, dir)
|
||
Log.Error("DIR", err.Error())
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
func FileDel(file string) error {
|
||
err := os.Remove(file)
|
||
if err != nil {
|
||
if !os.IsNotExist(err) {
|
||
err = fmt.Errorf("Delete Error:%v[%v]", err, file)
|
||
Log.Error("FILE", err.Error())
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
func FileCopy(srcfile string, dstfile string) error {
|
||
srcF, err := os.Open(srcfile)
|
||
if err != nil {
|
||
err = fmt.Errorf("copy open error:%v[%v]", err, srcfile)
|
||
Log.Error("FILE", err.Error())
|
||
return err
|
||
}
|
||
defer srcF.Close()
|
||
reader := bufio.NewReader(srcF)
|
||
|
||
dstF, err := os.OpenFile(dstfile, os.O_WRONLY|os.O_CREATE, 0644)
|
||
if err != nil {
|
||
err = fmt.Errorf("copy create error:%v[%v]", err, dstfile)
|
||
Log.Error("FILE", err.Error())
|
||
return err
|
||
}
|
||
defer dstF.Close()
|
||
writer := bufio.NewWriter(dstF)
|
||
_, err = io.Copy(writer, reader)
|
||
if err != nil {
|
||
err = fmt.Errorf("copy write error:%v[%v][%v]", err, srcfile, dstfile)
|
||
Log.Error("FILE", err.Error())
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
func FileSave(filename string, text any) error {
|
||
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer f.Close()
|
||
writer := bufio.NewWriter(f)
|
||
switch v := text.(type) {
|
||
case string:
|
||
_, err = writer.WriteString(v)
|
||
case []byte:
|
||
_, err = writer.Write(v)
|
||
case []string:
|
||
for _, s := range v {
|
||
_, err = writer.WriteString(s)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
default:
|
||
_, err = writer.WriteString(Tostr(v))
|
||
}
|
||
|
||
if err != nil {
|
||
return err
|
||
}
|
||
err = writer.Flush()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
func FileLoad(filename string) []string {
|
||
f, err := os.Open(filename)
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
defer f.Close()
|
||
|
||
scanner := bufio.NewScanner(f)
|
||
scanner.Split(bufio.ScanLines)
|
||
|
||
lines := make([]string, 0)
|
||
for scanner.Scan() {
|
||
lines = append(lines, scanner.Text())
|
||
}
|
||
return lines
|
||
}
|
||
func DirExist(pathname string) error {
|
||
info, err := os.Stat(pathname)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if info.IsDir() {
|
||
return nil
|
||
}
|
||
return fmt.Errorf("%s is not a directory", pathname)
|
||
}
|
||
func FileExist(filename string) error {
|
||
if _, err := os.Stat(filename); err == nil {
|
||
return nil
|
||
} else if os.IsNotExist(err) {
|
||
return err
|
||
}
|
||
return fmt.Errorf("%s is not a file", filename)
|
||
}
|
||
func Fileext(file string) (string, string) {
|
||
ind := strings.LastIndex(file, ".")
|
||
if ind == -1 {
|
||
return file, ""
|
||
}
|
||
|
||
return file[:ind], strings.ToLower(file[ind+1:])
|
||
}
|