package utils import ( "errors" "fmt" "github.com/lianggx6/goutf16" "io" "math/rand" "net/http" "os" "path" "path/filepath" "reflect" "regexp" "runtime" "strconv" "strings" "sync" "syscall" "time" "unsafe" ) type HWND uintptr const ( ERROR_FILE_NOT_FOUND = 2 ERROR_PATH_NOT_FOUND = 3 ERROR_BAD_FORMAT = 11 ) const ( SE_ERR_ACCESSDENIED = 5 SE_ERR_OOM = 8 SE_ERR_DLLNOTFOUND = 32 SE_ERR_SHARE = 26 SE_ERR_ASSOCINCOMPLETE = 27 SE_ERR_DDETIMEOUT = 28 SE_ERR_DDEFAIL = 29 SE_ERR_DDEBUSY = 30 SE_ERR_NOASSOC = 31 ) var ( modshell32 = syscall.NewLazyDLL("shell32.dll") procShellExecute = modshell32.NewProc("ShellExecuteW") ) // 判断文件夹是否存在 func PathExists(path string) (bool, error) { var err error if _, err = os.Stat(path); err == nil { return true, nil } if os.IsNotExist(err) { return false, nil } return false, err } // 用b的所有字段覆盖a的 // 如果fields不为空, 表示用b的特定字段覆盖a的 // a应该为结构体指针 func CopyFields(a interface{}, b interface{}, fields ...string) (err error) { at := reflect.TypeOf(a) av := reflect.ValueOf(a) bt := reflect.TypeOf(b) bv := reflect.ValueOf(b) // 简单判断下 if at.Kind() != reflect.Ptr { err = fmt.Errorf("a must be a struct pointer") return } av = reflect.ValueOf(av.Interface()) // 要复制哪些字段 _fields := make([]string, 0) if len(fields) > 0 { _fields = fields } else { for i := 0; i < bv.NumField(); i++ { _fields = append(_fields, bt.Field(i).Name) } } if len(_fields) == 0 { fmt.Println("no fields to copy") return } // 复制 for i := 0; i < len(_fields); i++ { name := _fields[i] f := av.Elem().FieldByName(name) bValue := bv.FieldByName(name) // a中有同名的字段并且类型一致才复制 if f.IsValid() && f.Kind() == bValue.Kind() { f.Set(bValue) } else { //fmt.Printf("no such field or different kind, fieldName: %s\n", name) } } return } //获取默认打印机 func GetDefaultPrinterName() (string, []uint16) { var ( dll = syscall.MustLoadDLL("winspool.drv") getDefaultPrinter = dll.MustFindProc("GetDefaultPrinterW") pn [256]uint16 ) plen := len(pn) getDefaultPrinter.Call(uintptr(unsafe.Pointer(&pn)), uintptr(unsafe.Pointer(&plen))) printerName := syscall.UTF16ToString(pn[:]) printer16 := goutf16.EncodeStringToUTF16(printerName) return printerName, printer16 } // 设置默认打印机 func SetDefaultPrinter(printerName string) error { var ( dll = syscall.MustLoadDLL("winspool.drv") setDefaultPrinter = dll.MustFindProc("SetDefaultPrinterW") p []uint16 pn [256]uint16 ) p = goutf16.EncodeStringToUTF16(printerName) pn = UintSliceTo256Uint(p) ret, _, msg := setDefaultPrinter.Call(uintptr(unsafe.Pointer(&pn))) if ret == 0 { return msg } return nil } func Uint16ToBytes(n uint16) []byte { return []byte{ byte(n), byte(n >> 8), } } func BytesToUint16(array []byte) uint16 { var data uint16 = 0 for i := 0; i < len(array); i++ { data = data + uint16(uint(array[i])< max: panic("min must be less than or equal to max") } return min + r.Intn(max-min) } // PanicToError Panic转换为error func PanicToError(f func()) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf(PanicTrace(e)) } }() f() return } // PanicTrace panic调用链跟踪 func PanicTrace(err interface{}) string { stackBuf := make([]byte, 4096) n := runtime.Stack(stackBuf, false) return fmt.Sprintf("panic: %v %s", err, stackBuf[:n]) } // DownloadFile 文件下载 func DownloadFile(filePath string, rw http.ResponseWriter) error { file, err := os.Open(filePath) if err != nil { return err } filename := path.Base(filePath) rw.Header().Set("Content-Type", "application/octet-stream") rw.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename)) _, err = io.Copy(rw, file) return err } // WorkDir 获取程序运行时根目录 func WorkDir() (string, error) { execPath, err := os.Executable() if err != nil { return "", err } wd := filepath.Dir(execPath) if filepath.Base(wd) == "bin" { wd = filepath.Dir(wd) } return wd, nil } // WaitGroupWrapper waitGroup包装 type WaitGroupWrapper struct { sync.WaitGroup } // Wrap 包装Add, Done方法 func (w *WaitGroupWrapper) Wrap(f func()) { w.Add(1) go func() { defer w.Done() f() }() } // 生成长度为length的随机字符串 func RandString(length int64) string { sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") var result []byte r := rand.New(rand.NewSource(time.Now().UnixNano())) sourceLength := len(sources) var i int64 = 0 for ; i < length; i++ { result = append(result, sources[r.Intn(sourceLength)]) } return string(result) } // 批量替换字符串 func ReplaceStrings(s string, old []string, replace []string) string { if s == "" { return s } if len(old) != len(replace) { return s } for i, v := range old { s = strings.Replace(s, v, replace[i], 1000) } return s } func InStringSlice(slice []string, element string) bool { element = strings.TrimSpace(element) for _, v := range slice { if strings.TrimSpace(v) == element { return true } } return false } // 转义json特殊字符 func EscapeJson(s string) string { specialChars := []string{"\\", "\b", "\f", "\n", "\r", "\t", "\""} replaceChars := []string{"\\\\", "\\b", "\\f", "\\n", "\\r", "\\t", "\\\""} return ReplaceStrings(s, specialChars, replaceChars) } // 判断文件是否存在及是否有权限访问 func FileExist(file string) bool { _, err := os.Stat(file) if os.IsNotExist(err) { return false } if os.IsPermission(err) { return false } return true } func Max(vals ...int) int { var max int for _, val := range vals { if val > max { max = val } } return max } func Min(vals ...int) int { var min int for _, val := range vals { if min == 0 || val <= min { min = val } } return min } func MaxTime(vals ...time.Time) time.Time { var max time.Time if len(vals) > 0 { max = vals[0] } else { // 默认返回一年前的时间 return time.Now().Add(24 * 265 * time.Second) } for _, val := range vals { if val.Unix() > max.Unix() { max = val } } return max } func MinTime(vals ...time.Time) time.Time { var min time.Time if len(vals) > 0 { min = vals[0] } else { // 默认返回一年前的时间 return time.Now().Add(24 * 265 * time.Second) } for _, val := range vals { if val.Unix() <= min.Unix() { min = val } } return min } func AddListOnce(list []string, element string) []string { isIn := false for _, info := range list { if info == element { isIn = true } } if !isIn { list = append(list, element) } return list } func Decimal(value float64,length int) float64 { if length <= 0{ length = 2 } format := "%."+strconv.Itoa(length)+"f" value, _ = strconv.ParseFloat(fmt.Sprintf(format, value), 64) return value }