|
|
- 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])<<uint(8*i))
- }
-
- return data
- }
-
- func UintSliceTo256Uint(us []uint16) (res [256]uint16) {
- var i int
-
- for i = 0; i < len(us); i++ {
- res[i] = us[i]
- }
- return res
- }
-
- func GetExcelCellIntPos(pos string) (row, col int, err error) {
- var (
- chareg, numreg *regexp.Regexp
- cha, num [][]string
- i int
- uc []rune
- rowstr string
- )
-
- chareg = regexp.MustCompile("[a-zA-Z]")
- numreg = regexp.MustCompile("[0-9]")
- cha = chareg.FindAllStringSubmatch(pos, -1)
- num = numreg.FindAllStringSubmatch(pos, -1)
- // 获取字符的列值
- col = 0
- for i = 0; i < len(cha); i++ {
- uc = []rune(strings.ToUpper(cha[i][0]))
- col = col + i*26 + (int(uc[0]) - 65)
- }
-
- // 获取行值
- for i = 0; i < len(num); i++ {
- rowstr = rowstr + num[i][0]
- }
- row, _ = strconv.Atoi(rowstr)
-
- return row - 1, col, nil
- }
-
- func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
- var op, param, directory uintptr
- if len(lpOperation) != 0 {
- op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
- }
- if len(lpParameters) != 0 {
- param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
- }
- if len(lpDirectory) != 0 {
- directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
- }
-
- ret, _, _ := procShellExecute.Call(
- uintptr(hwnd),
- op,
- uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
- param,
- directory,
- uintptr(nShowCmd))
-
- errorMsg := ""
- if ret != 0 && ret <= 32 {
- switch int(ret) {
- case ERROR_FILE_NOT_FOUND:
- errorMsg = "The specified file was not found."
- case ERROR_PATH_NOT_FOUND:
- errorMsg = "The specified path was not found."
- case ERROR_BAD_FORMAT:
- errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)."
- case SE_ERR_ACCESSDENIED:
- errorMsg = "The operating system denied access to the specified file."
- case SE_ERR_ASSOCINCOMPLETE:
- errorMsg = "The file name association is incomplete or invalid."
- case SE_ERR_DDEBUSY:
- errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed."
- case SE_ERR_DDEFAIL:
- errorMsg = "The DDE transaction failed."
- case SE_ERR_DDETIMEOUT:
- errorMsg = "The DDE transaction could not be completed because the request timed out."
- case SE_ERR_DLLNOTFOUND:
- errorMsg = "The specified DLL was not found."
- case SE_ERR_NOASSOC:
- errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable."
- case SE_ERR_OOM:
- errorMsg = "There was not enough memory to complete the operation."
- case SE_ERR_SHARE:
- errorMsg = "A sharing violation occurred."
- default:
- errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret)
- }
- } else {
- return nil
- }
-
- return errors.New(errorMsg)
- }
-
- // RandNumber 生成min - max之间的随机数
- // 如果min大于max, panic
- func RandNumber(min, max int) int {
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- switch {
- case min == max:
- return min
- case min > 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
- }
|