├── lang.go ├── .gitignore ├── nums.go ├── debug.go ├── README.md ├── nums_test.go ├── time.go ├── safemap.go ├── json.go ├── properties.go ├── string_test.go ├── region_test.go ├── image.go ├── ping.go ├── file.go ├── string.go ├── region.go ├── os.go ├── disk.go └── LICENSE /lang.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | // 本方法确保没错错误,如果有错误,则强制退出整个程序 4 | func NoError(err error) { 5 | if err != nil { 6 | panic(err) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /nums.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | // 返回byte(char)在数组中的位置 4 | func IndexOfBytes(array []byte, one byte) int { 5 | for i, entity := range array { 6 | if entity == one { 7 | return i 8 | } 9 | } 10 | return -1 11 | } 12 | 13 | // 返回字符串在数组中的位置 14 | func IndexOfStrings(array []string, one string) int { 15 | for i, entity := range array { 16 | if entity == one { 17 | return i 18 | } 19 | } 20 | return -1 21 | } 22 | 23 | // 判断字符串是否在数组中 24 | func IsInStrings(array []string, one string) bool { 25 | return IndexOfStrings(array, one) > -1 26 | } 27 | -------------------------------------------------------------------------------- /debug.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // 给一个总开关, 这样在调试的时候就可以使用总开关关闭打印语句了 8 | var _print_on_ bool = false 9 | 10 | func IsDebugOn() bool { 11 | return _print_on_ 12 | } 13 | 14 | func DebugOn() { 15 | _print_on_ = true 16 | } 17 | 18 | func DebugOff() { 19 | _print_on_ = false 20 | } 21 | 22 | func DebugPrint(a ...interface{}) (n int, err error) { 23 | if _print_on_ { 24 | return fmt.Print(a...) 25 | } 26 | return 0, nil 27 | } 28 | 29 | func DebugPrintf(format string, a ...interface{}) (n int, err error) { 30 | if _print_on_ { 31 | return fmt.Printf(format, a...) 32 | } 33 | return 0, nil 34 | } 35 | 36 | func DebugPrintln(a ...interface{}) (n int, err error) { 37 | if _print_on_ { 38 | return fmt.Println(a...) 39 | } 40 | return 0, nil 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | zgo 2 | === 3 | 4 | 提供一组 golang 的帮助函数集合,本项目是个代码库 5 | 6 | 7 | # 安装 8 | 9 | **自动安装** 10 | 11 | go get github.com/nutzam/zgo 12 | 13 | **手动安装** 14 | 15 | 自己手动从 github 下载代码后,放置在你的 $GOPATH 的 src/github.com/nutzam/zgo 目录下 16 | 17 | go install github.com/nutzam/zgo 18 | 19 | **安装成功的标志** 20 | 21 | 请检查你的 $GOPATH 是不是 22 | 23 | $GOPATH 24 | [src] 25 | [github.com] 26 | [nutzam] 27 | [zgo] # <- 这里是下载下来的源码 28 | REAME.md 29 | disk.go 30 | … 31 | [pkg] 32 | [github.com] 33 | [nutzam] 34 | zgo.a # <- 这里是编译好的包 35 | 36 | # 在你的项目里使用 37 | 38 | 在你的项目里你就能正常使用这个代码库了,具体如何使用,请参看 godoc 39 | 40 | package main 41 | 42 | import ( 43 | "fmt" 44 | z "github.com/nutzam/zgo" 45 | ) 46 | 47 | func main() { 48 | fmt.Println(z.Ph("~/my.txt")) 49 | } 50 | -------------------------------------------------------------------------------- /nums_test.go: -------------------------------------------------------------------------------- 1 | package z_test 2 | 3 | import ( 4 | z "github.com/nutzam/zgo" 5 | "testing" 6 | ) 7 | 8 | func Test_Index_Of_Bytes(t *testing.T) { 9 | bs := []byte{'a', 'b', 'c', 'e'} 10 | if z.IndexOfBytes(bs, 'b') != 1 { 11 | t.Error("b should be 1") 12 | } 13 | if z.IndexOfBytes(bs, 'e') != 3 { 14 | t.Error("e should be 3") 15 | } 16 | if z.IndexOfBytes(bs, 'z') != -1 { 17 | t.Error("e should be -1") 18 | } 19 | } 20 | 21 | func Test_Index_Of_Strings(t *testing.T) { 22 | bs := []string{"abc", "bcd", "cde", "efg"} 23 | if z.IndexOfStrings(bs, "bcd") != 1 { 24 | t.Error("bcd should be 1") 25 | } 26 | if z.IndexOfStrings(bs, "z123") != -1 { 27 | t.Error("z123 should be -1") 28 | } 29 | } 30 | 31 | func Test_Is_In_Strings(t *testing.T) { 32 | bs := []string{"abc", "bcd", "cde", "efg"} 33 | if !z.IsInStrings(bs, "bcd") { 34 | t.Error("bcd should be 1") 35 | } 36 | if z.IsInStrings(bs, "z123") { 37 | t.Error("z123 should be -1") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /time.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "strconv" 5 | "time" 6 | ) 7 | 8 | const FORMAT_DATE string = "2006-01-02" 9 | const FORMAT_DATE_TIME string = "2006-01-02 15:04:05" 10 | 11 | // 获取本地时间戳纳秒,以字符串格式返回 12 | func UnixNano() string { 13 | return strconv.FormatInt(time.Now().UnixNano(), 10) 14 | } 15 | 16 | // 获取本地事件毫秒 17 | func UnixMsSec(off int) int64 { 18 | return (time.Now().Unix() + int64(off)) * 1000 19 | } 20 | 21 | // 获取某个时间当天的绝对秒数 22 | func DAoffSec(t time.Time, off int) int { 23 | hour, min, sec := t.Clock() 24 | return hour*3600 + min*60 + sec + off 25 | } 26 | 27 | // 获取当天的绝对秒数,根据当前时间 +n 28 | func DAsec(off int) int { 29 | return DAoffSec(time.Now(), off) 30 | } 31 | 32 | // 获得当前系统时间 33 | func GetTime() string { 34 | return time.Now().Format(FORMAT_DATE_TIME) 35 | } 36 | 37 | func ParseDate(dstr string) time.Time { 38 | t, _ := time.Parse(FORMAT_DATE, dstr) 39 | return t 40 | } 41 | 42 | func ParseDateTime(dtstr string) time.Time { 43 | t, _ := time.Parse(FORMAT_DATE_TIME, dtstr) 44 | return t 45 | } 46 | -------------------------------------------------------------------------------- /safemap.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type BeeMap struct { 8 | lock *sync.RWMutex 9 | bm map[interface{}]interface{} 10 | } 11 | 12 | func NewBeeMap() *BeeMap { 13 | return &BeeMap{ 14 | lock: new(sync.RWMutex), 15 | bm: make(map[interface{}]interface{}), 16 | } 17 | } 18 | 19 | //Get from maps return the k's value 20 | func (m *BeeMap) Get(k interface{}) interface{} { 21 | m.lock.RLock() 22 | defer m.lock.RUnlock() 23 | if val, ok := m.bm[k]; ok { 24 | return val 25 | } 26 | return nil 27 | } 28 | 29 | // Maps the given key and value. Returns false 30 | // if the key is already in the map and changes nothing. 31 | func (m *BeeMap) Set(k interface{}, v interface{}) bool { 32 | m.lock.Lock() 33 | defer m.lock.Unlock() 34 | if val, ok := m.bm[k]; !ok { 35 | m.bm[k] = v 36 | } else if val != v { 37 | m.bm[k] = v 38 | } else { 39 | return false 40 | } 41 | return true 42 | } 43 | 44 | // Returns true if k is exist in the map. 45 | func (m *BeeMap) Check(k interface{}) bool { 46 | m.lock.RLock() 47 | defer m.lock.RUnlock() 48 | if _, ok := m.bm[k]; !ok { 49 | return false 50 | } 51 | return true 52 | } 53 | 54 | func (m *BeeMap) Delete(k interface{}) { 55 | m.lock.Lock() 56 | defer m.lock.Unlock() 57 | delete(m.bm, k) 58 | } 59 | -------------------------------------------------------------------------------- /json.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | simplejson "github.com/bitly/go-simplejson" 7 | "io" 8 | "log" 9 | "strings" 10 | ) 11 | 12 | // 解析 JSON,如果出错,则打印错误 13 | func JsonFromBytes(bs []byte, v interface{}) error { 14 | return JsonDecode(bytes.NewReader(bs), v) 15 | } 16 | 17 | // 将 JSON 字符串转换成一个对象 18 | func JsonFromString(str string, v interface{}) error { 19 | return JsonDecode(strings.NewReader(str), v) 20 | } 21 | 22 | // 解析 JSON,如果出错,则打印错误 23 | func JsonDecode(r io.Reader, v interface{}) error { 24 | err := json.NewDecoder(r).Decode(v) 25 | if nil != err { 26 | log.Println(err) 27 | } 28 | return err 29 | } 30 | 31 | // 将一个interface{}转换为一个simplejson.Json对象指针返回 32 | func InterfaceToJson(data *interface{}) (*simplejson.Json, error) { 33 | // 将interface转换为byte 34 | jsData, jsDataErr := json.Marshal(*data) 35 | if jsDataErr != nil { 36 | return nil, jsDataErr 37 | } 38 | js, jsonErr := ByteToJson(&jsData) 39 | if jsonErr != nil { 40 | return nil, jsonErr 41 | } 42 | return js, nil 43 | } 44 | 45 | // 将Byte转换为一个simplejson.Json对象指针返回 46 | func ByteToJson(data *[]byte) (*simplejson.Json, error) { 47 | // 解析JSON结构 48 | js, jsonErr := simplejson.NewJson(*data) 49 | if jsonErr != nil { 50 | return nil, jsonErr 51 | } 52 | // 返回对象 53 | return js, nil 54 | } 55 | -------------------------------------------------------------------------------- /properties.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | // 根据一个文件路径,解析 Nutz 的多行 properties 文件。 10 | // 这个文件必须是 utf-8 11 | func PPreadf(ph string) map[string]string { 12 | f, _ := os.Open(Ph(ph)) 13 | return PPread(f) 14 | } 15 | 16 | // 从一个流中解析一个 Nutz 的多行 properties 文件内容 17 | // 这个流必须是 utf-8 18 | func PPread(r io.Reader) (pp map[string]string) { 19 | // 准备返回值 20 | pp = make(map[string]string) 21 | // 读取文件全部内容 22 | str, _ := Utf8r(r) 23 | 24 | // fmt.Println(str) 25 | // fmt.Println(strings.Repeat("=", 80)) 26 | 27 | // 逐行分析 28 | lines := strings.Split(str, "\n") 29 | N := len(lines) 30 | for i := 0; i < N; i++ { 31 | line := lines[i] 32 | s := strings.TrimSpace(line) 33 | // 注释行 34 | switch { 35 | // 空行 36 | case len(s) == 0: 37 | continue 38 | // 注释行 39 | case strings.HasPrefix(s, "#"): 40 | continue 41 | // 多行模式 42 | case strings.HasSuffix(s, ":"): 43 | key := string(s[:len(s)-1]) 44 | from := i 45 | // 持续读取 46 | for ; i < N; i++ { 47 | line = lines[i] 48 | if strings.HasPrefix(line, "#") { 49 | break 50 | } 51 | } 52 | val := strings.Join(lines[from:i], "\n") 53 | pp[key] = val 54 | // 默认为名值对 55 | default: 56 | flds := strings.SplitN(s, "=", 2) 57 | if len(flds) == 1 { 58 | pp[strings.TrimSpace(flds[0])] = "" 59 | } else { 60 | pp[strings.TrimSpace(flds[0])] = strings.TrimSpace(flds[1]) 61 | } 62 | } 63 | } 64 | 65 | return 66 | } 67 | -------------------------------------------------------------------------------- /string_test.go: -------------------------------------------------------------------------------- 1 | package z_test 2 | 3 | import ( 4 | z "github.com/nutzam/zgo" 5 | "testing" 6 | ) 7 | 8 | func Test_Is_Space(t *testing.T) { 9 | if !z.IsSpace(' ') { 10 | t.Error("' ' is space") 11 | } 12 | if !z.IsSpace('\t') { 13 | t.Error("'\t' is space") 14 | } 15 | if !z.IsSpace('\n') { 16 | t.Error("'\n' is space") 17 | } 18 | if !z.IsSpace('\r') { 19 | t.Error("'\r' is space") 20 | } 21 | } 22 | 23 | func Test_Trim_Extra_Space(t *testing.T) { 24 | s1 := " a b c d\te \n" 25 | s2 := z.TrimExtraSpace(s1) 26 | if s2 != "a b c d e" { 27 | t.Errorf("can't trim [%s]", s1) 28 | } 29 | } 30 | 31 | func Test_Dup_Char(t *testing.T) { 32 | if z.DupChar('a', 5) != "aaaaa" { 33 | t.Error("DupChar 'a' 5 times != 'aaaaa'") 34 | } 35 | } 36 | 37 | func Test_Dup(t *testing.T) { 38 | if z.Dup("abc", 3) != "abcabcabc" { 39 | t.Error("Dup 'abc' 3 times != 'abcabcabc'") 40 | } 41 | } 42 | 43 | func Test_SBuilder(t *testing.T) { 44 | sb := z.StringBuilder() 45 | sb.Append("abc") 46 | if sb.String() != "abc" { 47 | t.Errorf("sb has error, should be %s, but be %s", "abc", sb.String()) 48 | } 49 | sb.Append('d') 50 | if sb.String() != "abcd" { 51 | t.Errorf("sb has error, should be %s, but be %s", "abcd", sb.String()) 52 | } 53 | if sb.Len() != 4 { 54 | t.Errorf("sb length should be 4, but be %d", sb.Len()) 55 | } 56 | sb2 := z.StringBuilder() 57 | sb2.Append([]string{"acb", "111", "gdgdg"}) 58 | if sb2.String() != "[acb 111 gdgdg]" { 59 | t.Errorf("sb2 has error, should be %s, but be %s", "[acb 111 gdgdg]", sb2.String()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /region_test.go: -------------------------------------------------------------------------------- 1 | package z_test 2 | 3 | import ( 4 | z "github.com/nutzam/zgo" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func Test_Region(t *testing.T) { 10 | 11 | z.DebugOn() 12 | 13 | r1 := new(z.Region) 14 | r1.Left = 18 15 | r1.Right = 55 16 | if r1.LeftInt() != 18 { 17 | t.Errorf("left should be %d", 18) 18 | } 19 | if r1.RightInt() != 55 { 20 | t.Errorf("right should be %d", 55) 21 | } 22 | 23 | t1 := time.Now() 24 | t2 := time.Date(2013, 9, 10, 11, 32, 50, 200, time.Local) 25 | r1.Left = time.Unix(t1.Unix(), 0) 26 | r1.Right = time.Unix(0, t2.UnixNano()) 27 | if r1.LeftDate().Unix() != t1.Unix() { 28 | t.Errorf("left should be %d, but be %d", t1.Unix(), r1.LeftDate().Unix()) 29 | } 30 | if r1.RightDate().UnixNano() != t2.UnixNano() { 31 | t.Errorf("right should be %d, but be %d", t2.UnixNano(), r1.RightDate().UnixNano()) 32 | } 33 | 34 | r2 := z.MakeRegion("[12355, 33535)") 35 | if r2.LeftOpen == true { 36 | t.Error("left should be close") 37 | } 38 | if r2.RightOpen == false { 39 | t.Error("right should be open") 40 | } 41 | if r2.Left != int(12355) { 42 | t.Error("left should be int 12355") 43 | } 44 | 45 | r3 := z.MakeRegion("[12.333, -0.555]") 46 | if r3.Left != float32(12.333) { 47 | t.Error("left should be float 12.333") 48 | } 49 | if r3.Right != float32(-0.555) { 50 | t.Error("right should be float -0.555, but be ", r3.Right) 51 | } 52 | 53 | r5 := z.MakeRegion("[2013-05-22 11:22:33, 2013-11-12 15:45:00]") 54 | if r5.LeftDate().Unix() != time.Date(2013, 5, 22, 11, 22, 33, 0, time.Local).Unix() { 55 | t.Error("left should be 2013-05-22 11:22:33") 56 | } 57 | 58 | r4 := z.MakeRegion("[2013-05-22, 2013-11-12]") 59 | if r4.LeftDate().Unix() != time.Date(2013, 5, 22, 0, 0, 0, 0, time.Local).Unix() { 60 | t.Error("left should be 2013-05-22") 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /image.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "image" 5 | "image/draw" 6 | "image/jpeg" 7 | "image/png" 8 | "os" 9 | ) 10 | 11 | // 读取JPEG图片返回image.Image对象 12 | func ImageJPEG(ph string) (image.Image, error) { 13 | // 打开图片文件 14 | f, fileErr := os.Open(ph) 15 | if fileErr != nil { 16 | return nil, fileErr 17 | } 18 | // 退出时关闭文件 19 | defer f.Close() 20 | // 解码 21 | j, jErr := jpeg.Decode(f) 22 | if jErr != nil { 23 | return nil, jErr 24 | } 25 | // 返回解码后的图片 26 | return j, nil 27 | } 28 | 29 | // 读取PNG图片返回image.Image对象 30 | func ImagePNG(ph string) (image.Image, error) { 31 | // 打开图片文件 32 | f, fileErr := os.Open(ph) 33 | if fileErr != nil { 34 | return nil, fileErr 35 | } 36 | // 退出时关闭文件 37 | defer f.Close() 38 | // 解码 39 | p, pErr := png.Decode(f) 40 | if pErr != nil { 41 | return nil, pErr 42 | } 43 | // 返回解码后的图片 44 | return p, nil 45 | } 46 | 47 | // 按照分辨率创建一张空白图片对象 48 | func ImageRGBA(width, height int) *image.RGBA { 49 | // 建立图像,image.Rect(最小X,最小Y,最大X,最小Y) 50 | return image.NewRGBA(image.Rect(0, 0, width, height)) 51 | } 52 | 53 | // 将图片绘制到图片 54 | func ImageDrawRGBA(img *image.RGBA, imgcode image.Image, x, y int) { 55 | // 绘制图像 56 | // image.Point A点的X,Y坐标,轴向右和向下增加{0,0} 57 | // image.ZP ZP is the zero Point 58 | // image.Pt Pt is shorthand for Point{X, Y} 59 | draw.Draw(img, img.Bounds(), imgcode, image.Pt(x, y), draw.Over) 60 | } 61 | 62 | // 将图片绘制到图片 63 | func ImageDrawRGBAOffSet(img *image.RGBA, imgcode image.Image, r image.Rectangle, x, y int) { 64 | // 绘制图像 65 | // image.Point A点的X,Y坐标,轴向右和向下增加{0,0} 66 | // image.ZP ZP is the zero Point 67 | // image.Pt Pt is shorthand for Point{X, Y} 68 | // r image.Rectangle img.Bounds() or img.Bounds().Add(offset) 69 | draw.Draw(img, r, imgcode, image.Pt(x, y), draw.Over) 70 | } 71 | 72 | // JPEG将编码生成图片 73 | // 选择编码参数,质量范围从1到100,更高的是更好 &jpeg.Options{90} 74 | func ImageEncodeJPEG(ph string, img image.Image, option int) error { 75 | // 确保文件父目录存在 76 | FcheckParents(ph) 77 | // 打开文件等待写入 78 | f := FileW(ph) 79 | // 保证文件正常关闭 80 | defer f.Close() 81 | // 写入文件 82 | return jpeg.Encode(f, img, &jpeg.Options{option}) 83 | } 84 | 85 | // PNG将编码生成图片 86 | func ImageEncodePNG(ph string, img image.Image) error { 87 | // 确保文件父目录存在 88 | FcheckParents(ph) 89 | // 打开文件等待写入 90 | f := FileW(ph) 91 | // 保证文件正常关闭 92 | defer f.Close() 93 | // 写入文件 94 | return png.Encode(f, img) 95 | } 96 | -------------------------------------------------------------------------------- /ping.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "bytes" 5 | "net" 6 | "os" 7 | "time" 8 | ) 9 | 10 | const ( 11 | ICMP_ECHO_REQUEST = 8 12 | ICMP_ECHO_REPLY = 0 13 | ) 14 | 15 | // Ping Request 16 | func makePingRequest(id, seq, pktlen int, filler []byte) []byte { 17 | p := make([]byte, pktlen) 18 | copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1)) 19 | 20 | p[0] = ICMP_ECHO_REQUEST // type 21 | p[1] = 0 // code 22 | p[2] = 0 // cksum 23 | p[3] = 0 // cksum 24 | p[4] = uint8(id >> 8) // id 25 | p[5] = uint8(id & 0xff) // id 26 | p[6] = uint8(seq >> 8) // sequence 27 | p[7] = uint8(seq & 0xff) // sequence 28 | 29 | // calculate icmp checksum 30 | cklen := len(p) 31 | s := uint32(0) 32 | for i := 0; i < (cklen - 1); i += 2 { 33 | s += uint32(p[i+1])<<8 | uint32(p[i]) 34 | } 35 | if cklen&1 == 1 { 36 | s += uint32(p[cklen-1]) 37 | } 38 | s = (s >> 16) + (s & 0xffff) 39 | s = s + (s >> 16) 40 | 41 | // place checksum back in header; using ^= avoids the 42 | // assumption the checksum bytes are zero 43 | p[2] ^= uint8(^s & 0xff) 44 | p[3] ^= uint8(^s >> 8) 45 | 46 | return p 47 | } 48 | 49 | func parsePingReply(p []byte) (id, seq int) { 50 | id = int(p[4])<<8 | int(p[5]) 51 | seq = int(p[6])<<8 | int(p[7]) 52 | return 53 | } 54 | 55 | // Ping 56 | func Ping(addr string, i int) bool { 57 | 58 | // *IPAddr 59 | raddr, e := net.ResolveIPAddr("ip4", addr) 60 | if e != nil { 61 | return false 62 | } 63 | 64 | // *IPConn 65 | ipconn, ee := net.DialIP("ip4:icmp", nil, raddr) 66 | if ee != nil { 67 | return false 68 | } 69 | 70 | // 保证连接正常关闭 71 | defer ipconn.Close() 72 | 73 | // PID 74 | sendid := os.Getpid() & 0xffff 75 | sendseq := 1 76 | pingpktlen := 64 77 | 78 | for { 79 | 80 | sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Ping")) 81 | 82 | // 发送请求 83 | n, err := ipconn.WriteToIP(sendpkt, raddr) 84 | if err != nil || n != pingpktlen { 85 | break 86 | } 87 | 88 | // 超时 89 | ipconn.SetDeadline(time.Now().Add(5 * time.Second)) 90 | 91 | // 返回数据 92 | resp := make([]byte, 1024) 93 | for { 94 | 95 | // 读取返回 96 | _, _, err := ipconn.ReadFrom(resp) 97 | if err != nil { 98 | break 99 | } 100 | 101 | // 判断状态 102 | if resp[0] != ICMP_ECHO_REPLY { 103 | continue 104 | } 105 | 106 | // 判断状态 107 | rcvid, rcvseq := parsePingReply(resp) 108 | if rcvid != sendid || rcvseq != sendseq { 109 | break 110 | } 111 | 112 | // 成功返回 113 | return true 114 | 115 | } 116 | 117 | // 执行次数内未成功返回 118 | if i == sendseq { 119 | break 120 | } 121 | 122 | // 计数器 123 | sendseq++ 124 | 125 | } 126 | 127 | // 失败返回 128 | return false 129 | } 130 | -------------------------------------------------------------------------------- /file.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | "path" 10 | ) 11 | 12 | // 按照 UTF8 格式化,将一个磁盘上的文件读成字符串 13 | func Utf8f(ph string) (str string, err error) { 14 | ph = Ph(ph) 15 | f, err := os.Open(ph) 16 | if nil != err { 17 | str = "" 18 | return 19 | } 20 | str, err = Utf8r(f) 21 | return 22 | } 23 | 24 | // 按照 UTF8 格式,将流的内容读成字符串 25 | func Utf8r(r io.Reader) (str string, err error) { 26 | bs, err := ioutil.ReadAll(r) 27 | if nil != err { 28 | str = "" 29 | return 30 | } 31 | str, err = Utf8(bs) 32 | return 33 | } 34 | 35 | // 便利的获得 FileInfo 对象的方法 36 | func Fi(ph string) os.FileInfo { 37 | ph = Ph(ph) 38 | f, e := os.Open(ph) 39 | NoError(e) 40 | return Fif(f) 41 | } 42 | 43 | // 便利的获得 FileInfo 对象的方法 44 | func Fif(f *os.File) os.FileInfo { 45 | fi, e := f.Stat() 46 | NoError(e) 47 | return fi 48 | } 49 | 50 | // 便利的获得文件大小的方法 51 | func Fszf(f *os.File) int64 { 52 | fi, e := f.Stat() 53 | NoError(e) 54 | return fi.Size() 55 | } 56 | 57 | // 便利的获得文件大小的方法 58 | func Fsz(ph string) int64 { 59 | ph = Ph(ph) 60 | f, e := os.Open(ph) 61 | NoError(e) 62 | return Fszf(f) 63 | } 64 | 65 | // Remove 文件 66 | func Fremove(ph string) (err error) { 67 | ph = Ph(ph) 68 | err = os.Remove(ph) 69 | return err 70 | } 71 | 72 | // 创建一个空文件,如果文件已存在,返回 false 73 | func Fnew(ph string) error { 74 | ph = Ph(ph) 75 | if Exists(ph) { 76 | return errors.New("file does not exist" + " " + ph) 77 | } 78 | // 确保父目录存在 79 | err := Mkdir(path.Dir(ph)) 80 | if err != nil { 81 | return err 82 | } 83 | // 创建 84 | _, err = os.Create(ph) 85 | if nil != err { 86 | return err 87 | } 88 | return nil 89 | } 90 | 91 | /* 92 | 调用者将负责关闭文件 93 | */ 94 | func FileA(ph string) *os.File { 95 | ph = Ph(ph) 96 | // 确定文件的父目录是存在的 97 | FcheckParents(ph) 98 | // 打开文件,文件不存在则创建,追加方式 99 | f, err := os.OpenFile(ph, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) 100 | if nil != err { 101 | panic(err) 102 | } 103 | return f 104 | } 105 | 106 | // 用回调的方式打文件以便追加内容,回调函数不需要关心文件关闭等问题 107 | func FileAF(ph string, callback func(*os.File)) { 108 | ph = Ph(ph) 109 | f := FileA(ph) 110 | if nil != f { 111 | defer f.Close() 112 | callback(f) 113 | } 114 | } 115 | 116 | // 打开一个文件准备复写内容,如果文件不存在,则创建它 117 | // 如果有错误,将打印 log 118 | // 119 | // 调用者将负责关闭文件 120 | func FileW(ph string) *os.File { 121 | ph = Ph(ph) 122 | // 确定文件的父目录是存在的 123 | FcheckParents(ph) 124 | // 打开文件 125 | f, err := os.OpenFile(ph, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) 126 | if nil != err { 127 | panic(err) 128 | } 129 | return f 130 | } 131 | 132 | // 用回调的方式打文件以便复写内容,回调函数不需要关心文件关闭等问题 133 | func FileWF(ph string, callback func(*os.File)) { 134 | ph = Ph(ph) 135 | f := FileW(ph) 136 | // 打开失败,那么将试图创建 137 | if nil == f && !Fexists(ph) { 138 | err := Fnew(ph) 139 | if err != nil { 140 | panic(err) 141 | } 142 | f = FileW(ph) 143 | } 144 | // 开始写入 145 | if nil != f { 146 | defer f.Close() 147 | if nil != callback { 148 | callback(f) 149 | } 150 | } 151 | } 152 | 153 | /* 154 | 将从自己磁盘目录,只读的方式打开一个文件。如果文件不存在,或者打开错误,则返回 nil。 155 | 如果有错误,将打印 log 156 | 157 | 调用者将负责关闭文件 158 | */ 159 | func FileR(ph string) *os.File { 160 | ph = Ph(ph) 161 | f, err := os.Open(ph) 162 | if nil != err { 163 | return nil 164 | } 165 | return f 166 | } 167 | 168 | // 用回调的方式打文件以便读取内容,回调函数不需要关心文件关闭等问题 169 | func FileRF(ph string, callback func(*os.File)) { 170 | ph = Ph(ph) 171 | f := FileR(ph) 172 | if nil != f { 173 | defer f.Close() 174 | callback(f) 175 | } 176 | } 177 | 178 | // 自定义模式打开文件 179 | // 如果有错误,将打印 log 并返回 nil 180 | // 调用者将负责关闭文件 181 | func FileO(ph string, flag int) *os.File { 182 | ph = Ph(ph) 183 | // 确定文件的父目录是存在的 184 | FcheckParents(ph) 185 | // 打开文件 186 | f, err := os.OpenFile(ph, flag, 0666) 187 | if nil != err { 188 | log.Println(err) 189 | return nil 190 | } 191 | return f 192 | } 193 | 194 | // 用自定义的模式打文件以便替换内容,回调函数不需要关心文件关闭等问题 195 | func FileOF(ph string, flag int, callback func(*os.File)) { 196 | ph = Ph(ph) 197 | f := FileO(ph, flag) 198 | // 开始写入 199 | if nil != f { 200 | defer f.Close() 201 | if nil != callback { 202 | callback(f) 203 | } 204 | } 205 | } 206 | 207 | // 强制覆盖写入文件 208 | func FWrite(path string, data []byte) error { 209 | // 保证目录存在 210 | FcheckParents(path) 211 | // 写入文件 212 | return ioutil.WriteFile(path, data, 0644) 213 | } 214 | -------------------------------------------------------------------------------- /string.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "strconv" 8 | "strings" 9 | "unicode/utf8" 10 | ) 11 | 12 | // 将一个字节数组转换成 utf-8 字符串 13 | func Utf8(bs []byte) (str string, err error) { 14 | if utf8.FullRune(bs) { 15 | //sz := utf8.RuneCount(bs) 16 | str = string(bs) 17 | return 18 | } 19 | // 错误 20 | err = errors.New("fail to decode to UTF8") 21 | str = "" 22 | return 23 | } 24 | 25 | // 是不是空字符 26 | func IsSpace(c byte) bool { 27 | if c >= 0x00 && c <= 0x20 { 28 | return true 29 | } 30 | return false 31 | } 32 | 33 | // 判断一个字符串是不是空白串,即(0x00 - 0x20 之内的字符均为空白字符) 34 | func IsBlank(s string) bool { 35 | for i := 0; i < len(s); i++ { 36 | b := s[i] 37 | if !IsSpace(b) { 38 | return false 39 | } 40 | } 41 | return true 42 | } 43 | 44 | // 如果输入的字符串为空串,那么返回默认字符串 45 | func SBlank(s, dft string) string { 46 | if IsBlank(s) { 47 | return dft 48 | } 49 | return s 50 | } 51 | 52 | // 将字符串转换成整数,如果转换失败,采用默认值 53 | func ToInt(s string, dft int) int { 54 | var re, err = strconv.Atoi(s) 55 | if err != nil { 56 | return dft 57 | } 58 | return re 59 | } 60 | 61 | // 将字符串转换成整数,如果转换失败,采用默认值 62 | func ToInt64(s string, dft int64) int64 { 63 | var re, err = strconv.ParseInt(s, 10, 64) 64 | if err != nil { 65 | return dft 66 | } 67 | return re 68 | } 69 | 70 | // 拆分字符串数组,如果数组元素为空白,忽略,否则则 Trim 空白 71 | func SplitIgnoreBlank(s, sep string) []string { 72 | ss := strings.Split(s, sep) 73 | size := len(ss) 74 | re := make([]string, 0, size) 75 | for i := 0; i < size; i++ { 76 | str := Trim(ss[i]) 77 | if len(str) > 0 { 78 | re = append(re, str) 79 | } 80 | } 81 | return re 82 | } 83 | 84 | // 去掉一个字符串左右的空白串,即(0x00 - 0x20 之内的字符均为空白字符) 85 | // 与strings.TrimSpace功能一致 86 | func Trim(s string) string { 87 | size := len(s) 88 | if size <= 0 { 89 | return s 90 | } 91 | l := 0 92 | for ; l < size; l++ { 93 | b := s[l] 94 | if !IsSpace(b) { 95 | break 96 | } 97 | } 98 | r := size - 1 99 | for ; r >= l; r-- { 100 | b := s[r] 101 | if !IsSpace(b) { 102 | break 103 | } 104 | } 105 | return string(s[l : r+1]) 106 | } 107 | 108 | // 去掉一个字符串左右的空白串,即(0x00 - 0x20 之内的字符均为空白字符) 109 | func TrimBytes(bs []byte) string { 110 | r := len(bs) - 1 111 | if r <= 0 { 112 | return string(bs) 113 | } 114 | l := 0 115 | for ; l <= r; l++ { 116 | b := bs[l] 117 | if !IsSpace(b) { 118 | break 119 | } 120 | } 121 | for ; r >= l; r-- { 122 | b := bs[r] 123 | if !IsSpace(b) { 124 | break 125 | } 126 | } 127 | return string(bs[l : r+1]) 128 | } 129 | 130 | // Trim并且去掉中间多余的空白(多个空白变一个空白) 131 | // 比如 " a b c d e" -> "a b c d e" 132 | func TrimExtraSpace(s string) string { 133 | s = Trim(s) 134 | size := len(s) 135 | switch size { 136 | case 0, 1, 2, 3: 137 | return s 138 | default: 139 | bs := make([]byte, 0, size) 140 | isSpace := false 141 | for i := 0; i < size; i++ { 142 | c := s[i] 143 | if !IsSpace(c) { 144 | if isSpace { 145 | bs = append(bs, ' ') 146 | isSpace = false 147 | } 148 | bs = append(bs, c) 149 | } else { 150 | if !isSpace { 151 | isSpace = true 152 | } 153 | } 154 | } 155 | return string(bs) 156 | } 157 | // 兼容低版本GO 158 | return "" 159 | } 160 | 161 | // 复制字符 162 | func DupChar(char byte, num int) string { 163 | bs := make([]byte, num, num) 164 | for i := 0; i < num; i++ { 165 | bs[i] = char 166 | } 167 | return string(bs) 168 | } 169 | 170 | // 复制字符串 171 | func Dup(str string, num int) string { 172 | return strings.Repeat(str, num) 173 | } 174 | 175 | // 填充字符串右侧一定数量的特殊字符 176 | func AlignLeft(str string, width int, char byte) string { 177 | length := len(str) 178 | if length < width { 179 | return str + DupChar(char, width-length) 180 | } 181 | return str 182 | } 183 | 184 | // 填充字符串左侧一定数量的特殊字符 185 | func AlignRight(str string, width int, char byte) string { 186 | length := len(str) 187 | if length < width { 188 | return DupChar(char, width-length) + str 189 | } 190 | return str 191 | } 192 | 193 | type strBuilder struct { 194 | buf *bytes.Buffer 195 | } 196 | 197 | // 提供一个类似java中stringBuilder对象,支持链式调用(不返回错误信息,直接panic) 198 | // str := SBuilder().Append("abc=123").Append('\n').String() 199 | // TODO 等着测试下性能,看看用字符数组来实现是不是效率高些 200 | func StringBuilder() *strBuilder { 201 | sb := new(strBuilder) 202 | sb.buf = bytes.NewBuffer(nil) 203 | return sb 204 | } 205 | 206 | // 添加任意可以生成string的东西 207 | func (sb *strBuilder) Append(o interface{}) *strBuilder { 208 | var err error 209 | switch o.(type) { 210 | case byte: 211 | b, _ := o.(byte) 212 | err = sb.buf.WriteByte(b) 213 | case rune: 214 | r, _ := o.(rune) 215 | _, err = sb.buf.WriteRune(r) 216 | default: 217 | str := fmt.Sprint(o) 218 | _, err = sb.buf.WriteString(str) 219 | } 220 | if err != nil { 221 | panic(err) 222 | } 223 | return sb 224 | } 225 | 226 | // 行结尾了换行(EOL End Of Line) 227 | func (sb *strBuilder) EOL() *strBuilder { 228 | sb.Append('\n') 229 | return sb 230 | } 231 | 232 | // 返回字符串 233 | func (sb *strBuilder) String() string { 234 | return sb.buf.String() 235 | } 236 | 237 | // 写入的字符串长度 238 | func (sb *strBuilder) Len() int { 239 | return sb.buf.Len() 240 | } 241 | 242 | // 字符串转Float 243 | func ToFloat(data string, reData float64) float64 { 244 | i, err := strconv.ParseFloat(data, 64) 245 | if err != nil { 246 | return reData 247 | } 248 | return i 249 | 250 | } 251 | -------------------------------------------------------------------------------- /region.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "errors" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | type rtype int 12 | 13 | const ( 14 | intRegion rtype = iota 15 | longRegion 16 | floatRegion 17 | float64Region 18 | dateRegion 19 | nilValue 20 | ) 21 | 22 | type Region struct { 23 | Left interface{} 24 | Right interface{} 25 | LeftOpen bool 26 | RightOpen bool 27 | _type_ rtype 28 | } 29 | 30 | func (r *Region) String() string { 31 | sb := StringBuilder() 32 | if r.LeftOpen { 33 | sb.Append("(") 34 | } else { 35 | sb.Append("[") 36 | } 37 | if r.HasLeft() { 38 | sb.Append(r.Left) 39 | } 40 | sb.Append(",") 41 | if r.HasRight() { 42 | sb.Append(r.Right) 43 | } 44 | if r.RightOpen { 45 | sb.Append(")") 46 | } else { 47 | sb.Append("]") 48 | } 49 | return sb.String() 50 | } 51 | 52 | // 正负整数 53 | const REX_INT string = "^(-?)(\\d+)$" 54 | 55 | // 正负浮点数 56 | const REX_FLOAT string = "^(-?)(\\d+)\\.(\\d+)$" 57 | 58 | // yyyy-MM-dd 59 | const REX_DATE string = "^([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))$" 60 | 61 | // yyyy-MM-dd hh:mm:ss 62 | const REX_DATE_TIME string = "([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))\\s+(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$" 63 | 64 | func MakeRegion(rstr string) *Region { 65 | r := new(Region) 66 | leftstr, rightstr, leftOpen, rightOpen := extractLeftAndRight(rstr) 67 | r.LeftOpen = leftOpen 68 | r.RightOpen = rightOpen 69 | 70 | var rt rtype 71 | r.Left, rt = toAppropriateType(leftstr) 72 | if rt != nilValue { 73 | r._type_ = rt 74 | } 75 | r.Right, rt = toAppropriateType(rightstr) 76 | if rt != nilValue { 77 | r._type_ = rt 78 | } 79 | 80 | return r 81 | } 82 | 83 | func toAppropriateType(str string) (interface{}, rtype) { 84 | 85 | // 空 86 | if IsBlank(str) { 87 | return nil, nilValue 88 | } else { 89 | str = Trim(str) 90 | } 91 | 92 | regInt := regexp.MustCompile(REX_INT) 93 | if regInt.MatchString(str) { 94 | sint, err1 := strconv.Atoi(str) 95 | if err1 != nil { 96 | sint64, err2 := strconv.ParseInt(str, 10, 64) 97 | if err2 != nil { 98 | panic(err2) 99 | } else { 100 | return sint64, longRegion 101 | } 102 | } else { 103 | return sint, intRegion 104 | } 105 | } 106 | regFloat := regexp.MustCompile(REX_FLOAT) 107 | if regFloat.MatchString(str) { 108 | sfloat, err1 := strconv.ParseFloat(str, 32) 109 | if err1 != nil { 110 | sfloat64, err2 := strconv.ParseFloat(str, 64) 111 | if err2 != nil { 112 | panic(err2) 113 | } else { 114 | return sfloat64, float64Region 115 | } 116 | } else { 117 | return float32(sfloat), floatRegion 118 | } 119 | } 120 | regDateTime := regexp.MustCompile(REX_DATE_TIME) 121 | if regDateTime.MatchString(str) { 122 | sdatetime, err1 := time.ParseInLocation("2006-01-02 15:04:05", TrimExtraSpace(str), time.Local) 123 | if err1 != nil { 124 | panic(err1) 125 | } else { 126 | return sdatetime, dateRegion 127 | } 128 | } 129 | regDate := regexp.MustCompile(REX_DATE) 130 | if regDate.MatchString(str) { 131 | sdate, err1 := time.ParseInLocation("2006-01-02", str, time.Local) 132 | if err1 != nil { 133 | panic(err1) 134 | } else { 135 | return sdate, dateRegion 136 | } 137 | } 138 | // 没有可以匹配的? 139 | panic(errors.New("not a region appropriate type, " + str)) 140 | } 141 | 142 | func extractLeftAndRight(rstr string) (left, right string, lopen, ropen bool) { 143 | lr := strings.Split(rstr, ",") 144 | if len(lr) == 2 { 145 | lopen = strings.HasPrefix(lr[0], "(") 146 | ropen = strings.HasSuffix(lr[1], ")") 147 | left = lr[0][1:] 148 | right = lr[1][:len(lr[1])-1] 149 | DebugPrintf("region (%s, %s, %v, %v)\n", left, right, lopen, ropen) 150 | // TODO 左右自动调整位置??? 151 | 152 | return 153 | } 154 | panic("wrong format for region, " + rstr) 155 | } 156 | 157 | func (r *Region) HasLeft() bool { 158 | return r.Left != nil 159 | } 160 | 161 | func (r *Region) HasRight() bool { 162 | return r.Right != nil 163 | } 164 | 165 | func (r *Region) LeftInt() int { 166 | nleft, ok := r.Left.(int) 167 | if ok { 168 | return nleft 169 | } 170 | panic("not int type") 171 | } 172 | 173 | func (r *Region) RightInt() int { 174 | nright, ok := r.Right.(int) 175 | if ok { 176 | return nright 177 | } 178 | panic("not int type") 179 | } 180 | 181 | func (r *Region) LeftLong() int64 { 182 | nleft, ok := r.Left.(int64) 183 | if ok { 184 | return nleft 185 | } 186 | panic("not long type") 187 | } 188 | 189 | func (r *Region) RightLong() int64 { 190 | nright, ok := r.Right.(int64) 191 | if ok { 192 | return nright 193 | } 194 | panic("not long type") 195 | } 196 | 197 | func (r *Region) LeftFloat() float32 { 198 | nleft, ok := r.Left.(float32) 199 | if ok { 200 | return nleft 201 | } 202 | panic("not float32 type") 203 | } 204 | 205 | func (r *Region) RightFloat() float32 { 206 | nright, ok := r.Right.(float32) 207 | if ok { 208 | return nright 209 | } 210 | panic("not float32 type") 211 | } 212 | 213 | func (r *Region) LeftFloat64() float64 { 214 | nleft, ok := r.Left.(float64) 215 | if ok { 216 | return nleft 217 | } 218 | panic("not float64 type") 219 | } 220 | 221 | func (r *Region) RightFloat64() float64 { 222 | nright, ok := r.Right.(float64) 223 | if ok { 224 | return nright 225 | } 226 | panic("not float64 type") 227 | } 228 | 229 | func (r *Region) LeftDate() time.Time { 230 | nleft, ok := r.Left.(time.Time) 231 | if ok { 232 | return nleft 233 | } 234 | panic("not date type") 235 | } 236 | 237 | func (r *Region) RightDate() time.Time { 238 | nright, ok := r.Right.(time.Time) 239 | if ok { 240 | return nright 241 | } 242 | panic("not date type") 243 | } 244 | -------------------------------------------------------------------------------- /os.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "archive/tar" 5 | "archive/zip" 6 | "bufio" 7 | "bytes" 8 | "compress/gzip" 9 | "crypto/md5" 10 | "crypto/sha1" 11 | "fmt" 12 | "hash" 13 | "io" 14 | "io/ioutil" 15 | "log" 16 | "os" 17 | "os/exec" 18 | "path/filepath" 19 | "regexp" 20 | "strings" 21 | ) 22 | 23 | // 获取本地MAC地址,只限Linux系统 24 | func GetMac() string { 25 | var mac string 26 | var stdout, stderr bytes.Buffer 27 | cmd := exec.Command("/sbin/ifconfig", "-a") 28 | cmd.Stdout = &stdout 29 | cmd.Stderr = &stderr 30 | cmd.Run() 31 | sOut := stdout.String() 32 | sErr := stderr.String() 33 | if len(sErr) == 0 { 34 | rx, _ := regexp.Compile("[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}") 35 | macStr := rx.FindString(strings.ToUpper(sOut)) 36 | str := strings.ToUpper(macStr) 37 | mac = strings.Replace(str, ":", "", -1) 38 | } else { 39 | log.Panic(sErr) 40 | } 41 | return Trim(mac) 42 | } 43 | 44 | func GetIntMac(v string) string { 45 | var mac string 46 | var stdout, stderr bytes.Buffer 47 | cmd := exec.Command("/sbin/ifconfig", v) 48 | cmd.Stdout = &stdout 49 | cmd.Stderr = &stderr 50 | cmd.Run() 51 | sOut := stdout.String() 52 | sErr := stderr.String() 53 | if len(sErr) == 0 { 54 | rx, _ := regexp.Compile("[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}") 55 | macStr := rx.FindString(strings.ToUpper(sOut)) 56 | str := strings.ToUpper(macStr) 57 | mac = strings.Replace(str, ":", "", -1) 58 | } else { 59 | log.Panic(sErr) 60 | } 61 | return Trim(mac) 62 | } 63 | 64 | // 计算一个文件的 MD5 指纹, 文件路径为磁盘绝对路径 65 | func MD5(ph string) string { 66 | return Finger(md5.New(), ph) 67 | } 68 | 69 | // 将磁盘某个文件按照某种算法计算成加密指纹 70 | func Finger(h hash.Hash, ph string) string { 71 | // 打开文件 72 | f, err := os.Open(ph) 73 | if err != nil { 74 | return "" 75 | } 76 | defer f.Close() 77 | // 读取 78 | io.Copy(h, bufio.NewReader(f)) 79 | // 返回计算结果 80 | return fmt.Sprintf("%x", h.Sum(nil)) 81 | } 82 | 83 | // 对字符串进行SHA1哈希 84 | func StrSHA1(data string) string { 85 | t := sha1.New() 86 | io.WriteString(t, data) 87 | return fmt.Sprintf("%x", t.Sum(nil)) 88 | } 89 | 90 | // 通过唯一时间的字符串,返回唯一的SHA1哈希 91 | func RandomSHA1() string { 92 | return StrSHA1(UnixNano()) 93 | } 94 | 95 | // 生成一个 UUID 字符串(小写,去掉减号),需要系统支持 "uuidgen" 命令 96 | // 返回的字符串格式如 "1694108edc6348b08364e604dee1bf35" 97 | func UU() string { 98 | return strings.Replace(UU16(), "-", "", -1) 99 | } 100 | 101 | // 生成一个 UUID 字符串(小写),需要系统支持 "uuidgen" 命令 102 | // 返回的字符串格式如 "1694108e-dc63-48b0-8364-e604dee1bf35" 103 | func UU16() string { 104 | bs, err := exec.Command("uuidgen").Output() 105 | if nil != err { 106 | log.Fatal("fail to found command 'uuidgen' in $PATH") 107 | } 108 | return strings.ToLower(TrimBytes(bs)) 109 | } 110 | 111 | // 解压Tar文件 112 | func Untar(file, path string) error { 113 | // 打开文件 114 | f, err := os.Open(file) 115 | if err != nil { 116 | return err 117 | } 118 | defer f.Close() 119 | // 读取GZIP 120 | gr, err := gzip.NewReader(f) 121 | if err != nil { 122 | return err 123 | } 124 | defer gr.Close() 125 | // 读取TAR 126 | tr := tar.NewReader(gr) 127 | for { 128 | hdr, err := tr.Next() 129 | if err == io.EOF { 130 | break 131 | } else if err != nil { 132 | return err 133 | } 134 | if hdr.FileInfo().IsDir() { 135 | os.MkdirAll(path+string(os.PathSeparator)+hdr.Name, hdr.FileInfo().Mode()) 136 | } else { 137 | fw, err := os.OpenFile(path+string(os.PathSeparator)+hdr.Name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, hdr.FileInfo().Mode()) 138 | if err != nil { 139 | return err 140 | } 141 | defer fw.Close() 142 | _, err = io.Copy(fw, tr) 143 | if err != nil { 144 | return err 145 | } 146 | } 147 | } 148 | return nil 149 | } 150 | 151 | // 运行命令脚本,只限Linux系统 152 | func LinuxCmd(sh string) error { 153 | var stderr bytes.Buffer 154 | var stdout bytes.Buffer 155 | cmd := exec.Command("/bin/sh", sh) 156 | cmd.Stdout = &stdout 157 | cmd.Stderr = &stderr 158 | err := cmd.Run() 159 | if err != nil { 160 | return fmt.Errorf("[%s] [%s]", sh, err) 161 | } 162 | sOut := stdout.String() 163 | if len(sOut) != 0 { 164 | log.Println(sOut) 165 | } 166 | sErr := stderr.String() 167 | if len(sErr) != 0 { 168 | return fmt.Errorf(sh, sErr) 169 | } 170 | return nil 171 | } 172 | 173 | // 运行系统命令,只限Linux系统 174 | func LinuxBash(sh string) error { 175 | var stderr bytes.Buffer 176 | var stdout bytes.Buffer 177 | cmd := exec.Command(sh) 178 | cmd.Stderr = &stderr 179 | cmd.Stdout = &stdout 180 | err := cmd.Run() 181 | if err != nil { 182 | return fmt.Errorf("[%s] [%s]", sh, err) 183 | } 184 | sOut := stdout.String() 185 | if len(sOut) != 0 { 186 | log.Println(sOut) 187 | } 188 | sErr := stderr.String() 189 | if len(sErr) != 0 { 190 | return fmt.Errorf(sErr) 191 | } 192 | return nil 193 | } 194 | 195 | // 创建压缩文件 196 | func CreateZip(path, ph string) error { 197 | // 创建写入缓冲区 198 | buf := new(bytes.Buffer) 199 | // 创建压缩缓冲区 200 | w := zip.NewWriter(buf) 201 | // 文件列表 202 | files := make([]string, 0) 203 | // 读取文件列表 204 | err := filepath.Walk(path, func(aph string, f os.FileInfo, err error) error { 205 | // 文件不存在 206 | if f == nil { 207 | return nil 208 | } 209 | // 跳过文件夹 210 | if f.IsDir() { 211 | return nil 212 | } 213 | files = append(files, Range(aph, len(path), len(aph))) 214 | return nil 215 | }) 216 | // 判断是否出错 217 | if err != nil { 218 | return err 219 | } 220 | // 将文件读取 221 | for _, file := range files { 222 | f, err := w.Create(file) 223 | if err != nil { 224 | return err 225 | } 226 | r, err := os.Open(path + "/" + file) 227 | if err != nil { 228 | return err 229 | } 230 | data, err := ioutil.ReadAll(r) 231 | if err != nil { 232 | return err 233 | } 234 | _, err = f.Write(data) 235 | if err != nil { 236 | return err 237 | } 238 | r.Close() 239 | } 240 | // 关闭缓冲区 241 | err = w.Close() 242 | if err != nil { 243 | return err 244 | } 245 | // 写入 246 | FileWF(ph, func(f *os.File) { 247 | f.Write(buf.Bytes()) 248 | }) 249 | // 返回 250 | return nil 251 | } 252 | 253 | // 字符串 254 | func Range(str string, start, end int) string { 255 | var data string 256 | for i, s := range str { 257 | if i >= start && i < end { 258 | data += string(s) 259 | } 260 | } 261 | return data 262 | } 263 | -------------------------------------------------------------------------------- /disk.go: -------------------------------------------------------------------------------- 1 | package z 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "os" 8 | "path" 9 | "path/filepath" 10 | "strings" 11 | ) 12 | 13 | // 根据给定路径获取绝对路径,可以支持 ~ 作为主目录 14 | func Ph(ph string) string { 15 | if IsBlank(ph) { 16 | return "" 17 | } 18 | if strings.HasPrefix(ph, "~") { 19 | home := os.Getenv("HOME") 20 | if IsBlank(home) { 21 | panic(fmt.Sprintf("can not found HOME in envs, '%s' AbsPh Failed!", ph)) 22 | } 23 | ph = fmt.Sprint(home, string(ph[1:])) 24 | } 25 | s, err := filepath.Abs(ph) 26 | if nil != err { 27 | panic(err) 28 | } 29 | return s 30 | } 31 | 32 | // 创建一个目录,如果目录存在或者创建成功,返回 true,否则返回 false 33 | func Mkdir(ph string) error { 34 | err := os.MkdirAll(ph, os.ModeDir|0755) 35 | if nil != err { 36 | return err 37 | } 38 | return err 39 | } 40 | 41 | // 判断一个路径是否存在 42 | func Exists(name string) bool { 43 | if _, err := os.Stat(name); err != nil { 44 | if os.IsNotExist(err) { 45 | return false 46 | } 47 | } 48 | return true 49 | } 50 | 51 | // 判断一个路径是否存在,且允许附加条件 52 | func ExistsF(name string, callback func(os.FileInfo) bool) bool { 53 | fi, err := os.Stat(name) 54 | if err != nil && os.IsNotExist(err) { 55 | return false 56 | } 57 | return callback(fi) 58 | } 59 | 60 | // 判断一个路径文件是否存在,且不是文件夹 61 | func ExistsIsFile(name string) bool { 62 | fi, err := os.Stat(name) 63 | if err != nil { 64 | if os.IsNotExist(err) { 65 | return false 66 | } 67 | } 68 | if fi.IsDir() { 69 | return false 70 | } 71 | return true 72 | } 73 | 74 | // 判断一个路径文件是否存在,且不是文件夹 75 | func ExistsIsDir(name string) bool { 76 | fi, err := os.Stat(name) 77 | if err != nil { 78 | if os.IsNotExist(err) { 79 | return false 80 | } 81 | } 82 | if !fi.IsDir() { 83 | return false 84 | } 85 | return true 86 | } 87 | 88 | // 判断一个文件是否存在,不存在则创建 89 | func ExistsFile(aph string) bool { 90 | if Exists(aph) { 91 | return false 92 | } 93 | // 确保父目录存在 94 | Mkdir(path.Dir(aph)) 95 | // 创建 96 | _, err := os.Create(aph) 97 | if nil != err { 98 | return false 99 | } 100 | return true 101 | } 102 | 103 | // 判断一个路径是否存在,不存在则创建 104 | func ExistsDir(name string) bool { 105 | if _, err := os.Stat(name); err != nil { 106 | if os.IsNotExist(err) { 107 | err := os.MkdirAll(name, os.ModeDir|0755) 108 | if nil != err { 109 | return false 110 | } 111 | return true 112 | } 113 | } 114 | return true 115 | } 116 | 117 | // 是否存在某一路径 118 | func Fexists(ph string) bool { 119 | return Exists(ph) 120 | } 121 | 122 | // 确保某个路径的父目录存在 123 | func FcheckParents(aph string) { 124 | pph := path.Dir(aph) 125 | err := os.MkdirAll(pph, os.ModeDir|0755) 126 | if nil != err { 127 | panic(err) 128 | } 129 | } 130 | 131 | // 读取多行属性文件,并将其变成一个 map,如果文件不存在,返回一个空 map 132 | func Properties(ph string) map[string]string { 133 | pp := make(map[string]string, 20) 134 | var f, e_open = os.Open(ph) 135 | // 文件不存在,那么创建默认的的配置信息 136 | if f == nil || e_open != nil { 137 | return pp 138 | } 139 | 140 | defer f.Close() 141 | 142 | r := bufio.NewReader(f) 143 | 144 | for { 145 | var line, e_read = r.ReadString('\n') 146 | // 出错或者读到文件结尾,退出循环 147 | if e_read == io.EOF || e_read != nil { 148 | break 149 | } 150 | // 去掉空白 151 | line = strings.TrimSpace(line) 152 | 153 | // 注释行跳过 154 | if strings.HasPrefix(line, "#") { 155 | continue 156 | } 157 | // 开始一个多行属性处理过程,会一直读到 "#" 开始的行 158 | if strings.HasSuffix(line, ":") { 159 | key := line[:len(line)-1] 160 | sb := make([]string, 0, 100) 161 | for { 162 | line, e_read = r.ReadString('\n') 163 | if e_read == io.EOF || e_read != nil { 164 | break 165 | } 166 | line = strings.TrimSpace(line) 167 | if strings.HasPrefix(line, "#") { 168 | break 169 | } 170 | sb = append(sb, line) 171 | } 172 | pp[key] = strings.Join(sb, "\n") 173 | continue 174 | } 175 | // 处理单行属性,= 作为分隔,如果没有,认为是空字符串 176 | ss := strings.SplitN(line, "=", 2) 177 | if len(ss) == 2 { 178 | pp[ss[0]] = ss[1] 179 | } else { 180 | pp[line] = "" 181 | } 182 | } 183 | return pp 184 | } 185 | 186 | // 文件夹中文件个数,单层目录 187 | func DirFileNum(ph string) int { 188 | // 计数器 189 | var i = 0 190 | // 遍历目录,获得主动事件 191 | filepath.Walk(ph, func(ph string, f os.FileInfo, err error) error { 192 | // 文件不存在 193 | if f == nil { 194 | return nil 195 | } 196 | f.Mode() 197 | // 跳过文件夹 198 | if f.IsDir() { 199 | return nil 200 | } 201 | // 文件 202 | i++ 203 | // 返回空 204 | return nil 205 | }) 206 | // 返回文件总量 207 | return i 208 | } 209 | 210 | // 删除一个文件,或者文件夹,如果该路径不存在,返回 false。 211 | // 如果是文件夹,递归删除 212 | func RemoveAll(ph string) error { 213 | return os.RemoveAll(ph) 214 | } 215 | 216 | // 移动文件或文件夹 217 | func Fmove(frompath, topath string) error { 218 | // 确保父目录存在 219 | FcheckParents(topath) 220 | // 移动 221 | e := os.Rename(frompath, topath) 222 | // 返回 223 | return e 224 | } 225 | 226 | // 通过文件结尾读取类型 227 | func FileType(name string) string { 228 | // 从文件名中读取文件格式 229 | fileName := strings.Split(name, ".") 230 | // 返回 231 | return fileName[len(fileName)-1] 232 | } 233 | 234 | // 遍历目录,尝试寻找指定开头文件 235 | func FindDirHeadFile(ph string, head string) string { 236 | // 保存找到的文件名称 237 | var name string 238 | // 遍历目录,获得主动事件 239 | filepath.Walk(ph, func(ph string, f os.FileInfo, err error) error { 240 | // 文件不存在 241 | if f == nil { 242 | return nil 243 | } 244 | // 跳过文件夹 245 | if f.IsDir() { 246 | return nil 247 | } 248 | // 判断文件名称是否为指定开头 249 | if strings.HasPrefix(f.Name(), head) { 250 | // 保存名称 251 | name = f.Name() 252 | } 253 | // 返回空 254 | return nil 255 | }) 256 | // 返回 257 | return name 258 | } 259 | 260 | // 拷贝文件 261 | func CopyFile(src, dst string) (err error) { 262 | FcheckParents(dst) 263 | srcFile, err := os.Open(src) 264 | if err != nil { 265 | return err 266 | } 267 | defer srcFile.Close() 268 | dstFile, err := os.Create(dst) 269 | if err != nil { 270 | return err 271 | } 272 | defer dstFile.Close() 273 | _, err = io.Copy(dstFile, srcFile) 274 | if err != nil { 275 | return err 276 | } 277 | return nil 278 | } 279 | 280 | // 目录大小 281 | func DirSize(path string) int64 { 282 | var size int64 283 | filepath.Walk(path, func(aph string, fi os.FileInfo, err error) error { 284 | if fi == nil { 285 | return nil 286 | } 287 | size += fi.Size() 288 | return nil 289 | }) 290 | return size 291 | } 292 | 293 | // 获取路径目录 294 | func DirName(path string) string { 295 | dirs := strings.Split(path, string(os.PathSeparator)) 296 | var dir string 297 | for i := 0; i < len(dirs)-1; i++ { 298 | if i == len(dirs)-2 { 299 | dir += dirs[i] 300 | } else { 301 | dir += dirs[i] + string(os.PathSeparator) 302 | } 303 | } 304 | return dir 305 | } 306 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | --------------------------------------------------------------------------------