GoLang
- 每個程式碼
.go
必須歸屬一個package- 歸屬同一個package之
.go
變數名稱不得重複- 歸屬同一個package之
.go
檔案必須位於同一資料夾- import導入package可自訂抬頭名稱,資料夾路徑為
%GOPATH%/src
目錄下- 若要將package編譯成執行檔,必須將主程式歸屬於
package main
當中,執行檔將由func init()
然後func main()
開始執行。func init()
由import內引用package的倒序開始執行,再依自身包func init()
順序開始執行(同一包可准許內有多個func init()
)。Package使用範例:
digraph{ nodesep=0.5 ranksep=0.5 graph [bgcolor="#1e1e1e"] edge [ color="#DDDDDD"] node [ color="#3e4045" penwidth=10 fillcolor="#3e4045" fontcolor="#DDDDDD" style=filled shape=ellipse fixedsize=true width=1.9] "\%GOPATH\%\" -> "src\" -> "Lesson2\" -> "Package演示\" -> {"Package_FolderTest1\" "Package_FolderTest2\" "Package_FolderTest3\"} "Package演示\" -> "Package_main.go" [fillcolor=Blue] "Package_FolderTest1\" -> "Package_Test1.go" [fillcolor=Blue] "Package_FolderTest2\" -> {"Package_Test2-1.go" "Package_Test2-2.go"} [fillcolor=Blue] "Package_FolderTest3\" -> {"Package_Test3-1.go" "Package_Test3-2.go"} [fillcolor=Blue] }
Package_main.go:
package main import ( Package_CustomTest1 "Lesson2/Package演示/Package_FolderTest1" Package_CustomTest2 "Lesson2/Package演示/Package_FolderTest2" Package_CustomTest3 "Lesson2/Package演示/Package_FolderTest3" "fmt" ) func main() { fmt.Println(Package_CustomTest1.Gstring_Name_Test1) fmt.Println(Package_CustomTest2.Gstring_Name_Test2_1) fmt.Println(Package_CustomTest2.Gstring_Name_Test2_2) fmt.Println(Package_CustomTest3.Gstring_Name_Test2_1) fmt.Println(Package_CustomTest3.Gstring_Name_Test2_2) }
Package_Test1.go:
//package main可透過import導入並使用大寫開頭名稱之變數 //package main不可由import導入小寫開頭名稱之變數 package Package_Test1 var gstring_Name_Test0 = "不可import" var Gstring_Name_Test1 = "測試1"
Package_Test2-1.go:
//歸屬同一個package(同目錄)的Package_Test2-1.go之變數名稱不得重複 package Package_Test2 var Gstring_Name_Test2_1 = "測試2-1"
Package_Test2-2.go:
//歸屬同一個package(同目錄)的Package_Test2-2.go之變數名稱不得重複複 package Package_Test2 var Gstring_Name_Test2_2 = "測試2-2"
Package_Test3-1.go:
//package main可使用import更名避免重複的package名稱 package Package_Test2 var Gstring_Name_Test2_1 = "測試2-1"
Package_Test2-2.go:
//package main可使用import更名避免重複的package名稱 package Package_Test2 var Gstring_Name_Test2_2 = "測試2-2"
package main import ( "fmt" "log" "runtime"package main import ( "fmt" "log" "runtime" ) func main() { var m0 runtime.MemStats println() log.Println("At begin:") PrintMemUsage(m0) // 2020/04/06 11:09:40 At begin: // Alloc(當前堆上對象佔用的內存大小) = 0 MiB // Sys(程序從作業系統總共申請的內存大小) = 6 MiB // NumGC(垃圾回收運行的次數) = 0 var m1 runtime.MemStats var overall1 []float64 for i := 0; i < 1136640; i++ { overall1 = append(overall1, 1) } println() log.Println("nothing to do:") PrintMemUsage(m1) println(overall1) overall1 = nil //僅為了計算方便,不影響測試結果 // 2020/04/06 11:09:40 nothing to do: // Alloc(當前堆上對象佔用的內存大小) = 8 MiB // Sys(程序從作業系統總共申請的內存大小) = 37 MiB // NumGC(垃圾回收運行的次數) = 9 // [1136640/1136640]0xc00127c000 var m2 runtime.MemStats var overall2 []float64 for i := 0; i < 1136640; i++ { overall2 = append(overall2, 1) } overall2 = nil println() log.Println("nil :") PrintMemUsage(m2) println(overall2) // 2020/04/06 11:09:40 nil : // Alloc(當前堆上對象佔用的內存大小) = 0 MiB // Sys(程序從作業系統總共申請的內存大小) = 37 MiB // NumGC(垃圾回收運行的次數) = 17 // [0/0]0x0 // Force GC to clear up, should see a memory drop var m3 runtime.MemStats var overall3 []float64 for i := 0; i < 1136640; i++ { overall3 = append(overall3, 1) } runtime.GC() println() log.Println("Forece GC:") PrintMemUsage(m3) // 2020/04/06 11:09:40 Forece GC: // Alloc(當前堆上對象佔用的內存大小) = 0 MiB // Sys(程序從作業系統總共申請的內存大小) = 37 MiB // NumGC(垃圾回收運行的次數) = 27 var m4 runtime.MemStats var overall4 []float64 p4 := &overall4 for i := 0; i < 1136640; i++ { overall4 = append(overall4, 1) } runtime.GC() println() log.Println("Forece GC (use pointer):") PrintMemUsage(m4) println(p4) // 2020/04/06 11:09:40 Forece GC: // Alloc(當前堆上對象佔用的內存大小) = 8 MiB // Sys(程序從作業系統總共申請的內存大小) = 37 MiB // NumGC(垃圾回收運行的次數) = 37 // 0xc00010ff60 } func PrintMemUsage(m runtime.MemStats) { runtime.ReadMemStats(&m) // For info on each, see: https://golang.org/pkg/runtime/#MemStats fmt.Printf("Alloc(當前堆上對象佔用的內存大小) = %v MiB\n", byteToMiB(m.Alloc)) //fmt.Printf("TotalAlloc(堆上總共分配出的內存大小) = %v MiB\n", byteToMiB(m.TotalAlloc)) fmt.Printf("Sys(程序從作業系統總共申請的內存大小) = %v MiB\n", byteToMiB(m.Sys)) fmt.Printf("NumGC(垃圾回收運行的次數) = %v\n", m.NumGC) } func byteToMiB(b uint64) uint64 { return b / 1024 / 1024 }
氣泡排序演算法的運作如下: 1.比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。 2.對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。 這步做完後,最後的元素會是最大的數。 3.針對所有的元素重複以上的步驟,除了最後一個。 4.持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
package main import "fmt" func main() { var vSlice = []int{51, 99, 36, 66, 62} fmt.Println("排序前:", vSlice) fmt.Println("最後結果:", fcBubbleSort_Slice(vSlice)) } func fcBubbleSort_Slice(inputSlice []int) []int { for index1 := 1; index1 < len(inputSlice); index1++ { // 第一層迴圈負責控制排序輪迴數 // 每輪都從第二個元素開始,將最大的值交換到最後一位 for index2 := 0; index2 < len(inputSlice)-index1; index2++ { // 第二層迴圈負責比較兩元素大小判斷是否交換 if inputSlice[index2] > inputSlice[index2+1] { inputSlice[index2], inputSlice[index2+1] = inputSlice[index2+1], inputSlice[index2] } } fmt.Printf("第%v次排序結果: %v\n", index1, inputSlice) } return inputSlice }
package main import ( "fmt" "reflect" ) func fc_ReflectExample1(if_input interface{}) { fmt.Printf("%v (%T)\n", reflect.ValueOf(if_input), reflect.ValueOf(if_input)) var vi_int = 1 + reflect.ValueOf(if_input).Int() //使用反射之內建方法進行型別斷言 fmt.Printf("%v (%T)\n", vi_int, vi_int) } type ty_Custom struct { Name string ID uint } func fc_ReflectExample2(if_input interface{}) { if st_Custom, TypePass := if_input.(ty_Custom); TypePass { fmt.Printf("%v (%T)\n", st_Custom, st_Custom) fmt.Printf("%v (%T)\n", st_Custom.Name, st_Custom.Name) } } func main() { fc_ReflectExample1(9) println() fc_ReflectExample2(ty_Custom{Name: "測試"}) // 9 (reflect.Value) // 10 (int64) // {測試 0} (main.ty_Custom) // 測試 (string }reflect包常用函式與方法:
函式名稱 說明 輸入 輸出類型 reflect.ValueOf(任意變數) 回傳變數值 任意變數 (reflect.Value) reflect.TypeOf(任意變數) 回傳變數型別名稱 任意變數 (*reflect.rtype) (reflect.Value型別變數).Kind() 回傳變數底層型別 reflect.Value型別 (string) (reflect.Value型別變數).Elem() 回傳指標之變數值 具備指標型別 (reflect.Value)) (reflect.Value型別變數).Elem().FieldByName(屬性名稱) 回傳結構體該屬性值 (reflect.Value型別)和屬性名稱 (reflect.Value) (reflect.Value型別變數名稱).CanSet() 判斷該變數是否能修改值 reflect.Value型別 (bool) (reflect.Value型別變數名稱).Set(reflect.Value(數值)) 直接修改該變數值 符合型別之數值 (*reflect.rtype).Name() 回傳變數型別名稱 (*reflect.rtype) 型別名稱(string) #### reflect Kind() 反射type型別名稱常數 const ( Invalid Kind = iota //nil屬此類 Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer )
package main import ( "fmt" "reflect" ) func fc_ReflectExample1(if_input interface{}) { fmt.Printf("%v (%T)\n", reflect.ValueOf(if_input), reflect.ValueOf(if_input)) var vi_int = 1 + reflect.ValueOf(if_input).Int() //使用反射之內建方法進行型別斷言 fmt.Printf("%v (%T)\n", vi_int, vi_int) } type ty_Custom struct { Name string ID uint } func fc_ReflectExample2(if_input interface{}) { if st_Custom, TypePass := if_input.(ty_Custom); TypePass { fmt.Printf("%v (%T)\n", st_Custom, st_Custom) fmt.Printf("%v (%T)\n", st_Custom.Name, st_Custom.Name) } } func main() { fc_ReflectExample1(9) println() fc_ReflectExample2(ty_Custom{Name: "測試"}) // 9 (reflect.Value) // 10 (int64) // {測試 0} (main.ty_Custom) // 測試 (string }Go 反射包(reflect)應用:
package main import ( "fmt" "reflect" ) type ty_Example struct { F0 uint F1 string } func main() { fmt.Printf("%v\n", reflect.ValueOf("Testing")) //Testing fmt.Printf("%T\n", reflect.ValueOf("Testing")) //reflect.Value fmt.Printf("%v\n", reflect.ValueOf("Testing").Kind()) //string fmt.Printf("%T\n", reflect.ValueOf("Testing").Kind()) //reflect.Kind //fmt.Printf("%v\n", reflect.ValueOf("Testing").Elem()) //panic: reflect: call of reflect.Value.Elem on string Value println() var vi_int int = 1 //var rVO = reflect.ValueOf(&vi_int) var vipr_int *int = &vi_int var rVO = reflect.ValueOf(vipr_int) fmt.Printf("%v\n", rVO.Elem()) //1 fmt.Printf("%T\n", rVO.Elem()) //reflect.Value fmt.Printf("%v\n", rVO.Elem().CanSet()) //true fmt.Printf("%T\n", rVO.Elem().CanSet()) //bool rVO.Elem().Set(reflect.ValueOf(99)) println(vi_int) //99 println() var st_Example = ty_Example{F0: 1, F1: "測試"} fmt.Printf("%v\n", reflect.ValueOf(&st_Example).CanSet()) //false fmt.Printf("%T\n", reflect.ValueOf(&st_Example).CanSet()) //bool fmt.Printf("%v\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1")) //測試 fmt.Printf("%T\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1")) //reflect.Value fmt.Printf("%v\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1").CanSet()) //true fmt.Printf("%T\n", reflect.ValueOf(&st_Example).Elem().FieldByName("F1").CanSet()) //bool reflect.ValueOf(&st_Example).Elem().FieldByName("F1").Set(reflect.ValueOf("修改")) fmt.Println(st_Example) //{1 修改} println() }
package main import ( "fmt" "reflect" ) type ty_Json struct { Name string `json:"jsname"` Age int `json:"jsage"` } func main() { st_User := ty_Json{ "測試", 20, } fmt.Println(reflect.TypeOf(st_User)) //(0x4adaa0,0x487ba0) fmt.Println(reflect.TypeOf(st_User).Field(0).Name) //name fmt.Println(reflect.TypeOf(st_User).Field(0).Type) //string fmt.Println(reflect.TypeOf(st_User).Field(0).Tag) //json:"jsname" fmt.Println(reflect.ValueOf(st_User).FieldByName("Name")) //測試 fmt.Println(reflect.ValueOf(st_User).FieldByName("Name").Type()) //測試 println() for index := 0; index < reflect.ValueOf(st_User).NumField(); index++ { if reflect.ValueOf(st_User).Field(index).CanInterface() { //判斷是否可導出屬性 fmt.Printf("%v (%v %v %v)\n", reflect.ValueOf(st_User).Field(index).Interface(), reflect.TypeOf(st_User).Field(index).Name, reflect.TypeOf(st_User).Field(index).Type, reflect.TypeOf(st_User).Field(index).Tag) } } // 測試 (Name string json:"jsname") // 20 (Age int json:"jsage") }
官方文檔: Golang → package time → type Duration 內建計時常數如下(const):
Nanosecond Duration = 1 (最小計時單位) Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minute
編譯時使用計時常數不可作除法運算(設計目的是為了避免影響精確度)
package main import ( "fmt" "time" ) func main() { vNow := time.Now() fmt.Printf("vNow = %v (%T)\n", vNow, vNow) fmt.Printf("年 = %v (%T)\n", vNow.Year(), vNow.Year()) fmt.Printf("月 = %v (%T)\n", vNow.Month(), vNow.Month()) fmt.Printf("月 = %v (%T)\n", int(vNow.Month()), int(vNow.Month())) fmt.Printf("日 = %v (%T)\n", vNow.Day(), vNow.Day()) fmt.Printf("星期 = %v (%T)\n", vNow.Weekday(), vNow.Weekday()) fmt.Printf("小時 = %v (%T)\n", vNow.Hour(), vNow.Hour()) fmt.Printf("分鐘 = %v (%T)\n", vNow.Minute(), vNow.Minute()) fmt.Printf("秒 = %v (%T)\n", vNow.Second(), vNow.Second()) fmt.Printf("當前時間 %04d-%02d-%02d(星期%02d) %02d:%02d:%02d\n", time.Now().Year(), int(time.Now().Month()), time.Now().Day(), time.Now().Weekday(), vNow.Hour(), vNow.Minute(), vNow.Second()) fmt.Printf(vNow.Format("2006/01/02 15:04:05") + "\n") fmt.Printf(vNow.Format("2006/01/02") + "\n") fmt.Printf(vNow.Format("15:04:05") + "\n") fmt.Printf("Unix時間戳:%v UnixNano時間戳%v\n", vNow.Unix(), vNow.UnixNano()) vCounterA := fcStartTimeCounter(0) //計數5秒鐘 for i := 0; i < 5; i++ { fmt.Println(i, "秒") time.Sleep(time.Second) } fmt.Printf("總共經過了: %0.3f秒\n", float64(fcStopTimeCounter(vCounterA))/(1000*1000*1000)) vCounterB := time.Now() for i := 0; i < 5; i++ { fmt.Println(i, "秒") time.Sleep(time.Second) } fmt.Printf("總共經過了: %0.3f秒\n",time.Now().Sub(vCounterB).Seconds()) } // const ( // Nanosecond Duration = 1 // Microsecond = 1000 * Nanosecond // Millisecond = 1000 * Microsecond // Second = 1000 * Millisecond // Minute = 60 * Second // Hour = 60 * Minute // ) func fcStartTimeCounter(input int64) int64 { fmt.Printf("\n計時開始由 %0.3f 秒開始計時", float64(input)/(1000^3)) return time.Now().UnixNano() + input } func fcStopTimeCounter(input int64) int64 { return time.Now().UnixNano() - input }Go 官方json包(json):
package main import ( "encoding/json" "fmt" ) type User struct { ID int Name string Money float64 Skills []string Relationship map[string]string Identification Identification } type Identification struct { Phone bool Email bool } func main() { user := User{ ID: 1, Name: "Tony", Skills: []string{"program", "rich", "play"}, Relationship: map[string]string{ "Dad": "Hulk", "Mon": "Natasha", }, Identification: Identification{ Phone: true, Email: false, }, } b, err := json.Marshal(user) if err != nil { fmt.Println("error:", err) } fmt.Println(string(b)) //{"ID":1,"Name":"Tony","Money":0,"Skills":["program","rich","play"],"Relationship":{"Dad":"Hulk","Mon":"Natasha"},"Identification":{"Phone":true,"Email":false}} } package main import ( "encoding/json" "fmt" ) type User struct { ID int Name string Money float64 Skills []string Relationship map[string]string Identification Identification } type Identification struct { Phone bool `json:"phone"` Email bool `json:"email,E-Mail"` } func main() { var jsonBlob = []byte(`{"ID":1,"Name":"Tony","Money":0,"Skills":["program","rich","play"],"Relationship":{"Dad":"Hulk","Mon":"Natasha"},"Identification":{"phone":true,"E-Mail":false}}`) var user User err := json.Unmarshal(jsonBlob, &user) if err != nil { fmt.Println("error:", err) } fmt.Printf("%+v", user) //{ID:1 Name:Tony Money:0 Skills:[program rich play] Relationship:map[Dad:Hulk Mon:Natasha] Identification:{Phone:true Email:false}} } package main import ( "encoding/json" "fmt" ) type User struct { ID int Name string Money float64 `json:",string"` Skills []string Relationship map[string]string Identification Identification Career string Responsibility interface {} } type Identification struct { Phone bool `json:"phone"` Email bool `json:"email"` } func main() { var jsonBlob = []byte(`[ { "ID":1, "Name":"Tony", "Career":"Engineer", "Responsibility":{ "skill":"PHP&Golang&Network", "description":"coding" } }, { "ID":2, "Name":"Jim", "Career":"Manager", "Responsibility":{ "experienced":true } } ]`) var users []User if err := json.Unmarshal(jsonBlob, &users); err != nil { fmt.Println("error:", err) } fmt.Printf("%#v\n", users) //[]main.User{main.User{ID:1, Name:"Tony", Money:0, Skills:[]string(nil), Relationship:map[string]string(nil), Identification:main.Identification{Phone:false, Email:false}, Career:"Engineer", Responsibility:map[string]interface {}{"description":"coding", "skill":"PHP&Golang&Network"}}, main.User{ID:2, Name:"Jim", Money:0, Skills:[]string(nil), Relationship:map[string]string(nil), Identification:main.Identification{Phone:false, Email:false}, Career:"Manager", Responsibility:map[string]interface {}{"experienced":true}}} fmt.Println(users[0].Responsibility.(map[string]interface{})["description"].(string)) //coding fmt.Println(users[1].Responsibility.(map[string]interface{})["experienced"].(bool)) //true } package main import ( "encoding/json" "fmt" ) type User struct { ID int Name string Money float64 `json:",string"` Skills []string Relationship map[string]string Identification Identification Career string Responsibility json.RawMessage } type Identification struct { Phone bool `json:"phone"` Email bool `json:"email"` } type Engineer struct { Skill string `json:"skill"` Description string `json:"description"` } type Manager struct { Experienced bool `json:"experienced"` } func main() { var jsonBlob = []byte(`[ { "ID":1, "Name":"Tony", "Career":"Engineer", "Responsibility":{ "skill":"PHP&Golang&Network", "description":"coding" } }, { "ID":2, "Name":"Jim", "Career":"Manager", "Responsibility":{ "experienced":true } } ]`) var users []User if err := json.Unmarshal(jsonBlob, &users); err != nil { fmt.Println("error:", err) } for _, user := range users { switch user.Career { case "Engineer": var responsibility Engineer if err := json.Unmarshal(user.Responsibility, &responsibility); err != nil { fmt.Println("error:", err) } fmt.Println(responsibility.Description) //coding case "Manager": var responsibility Manager if err := json.Unmarshal(user.Responsibility, &responsibility); err != nil { fmt.Println("error:", err) } fmt.Println(responsibility.Experienced) //true default: fmt.Println("warning:", "don't exist") } } }
os.file包使用說明:
函式名稱 說明 輸入 輸出類型:::: os.Open(路徑) 打開路徑中的檔案,並將輸出該文件的指標 (string) (*file error) (*file).Close() 將關閉file指標所指向檔案,移除移除該file指標 (string) (error) package FileSystem import ( "bufio" "errors" "io" "io/ioutil" "net/http" "os" "strconv" ) // os.O_WRONLY: 只寫 // os.O_CREATE: 創建文件(如果文件不存在) // os.O_RDONLY: 只讀 // os.O_RDWR: 讀寫皆可 // os.O_APPEND: 尾部加入 // os.O_TRUNC: 清空(文件存在情況下) // 第三個參數設置權限控制 func fc_GetPWD() string { vs_WorkingDir, _ := os.Getwd() return vs_WorkingDir } func fc_SetPWD(FilePathInput string) error { err := os.Chdir(FilePathInput) return err } func fc_GetEnv(EnvVarName string) (EnvVarValue string) { return os.Getenv(EnvVarName) } func fc_GetAllEnv(EnvVarName string) (AllEnvVarValues []string) { return os.Environ() } func fc_GetPathList(FilePathInput string) (FolderList []string, err error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return FolderList, err } ty_FileInfos, err := pty_OpenFile.Readdir(-1) pty_OpenFile.Close() if err != nil { return FolderList, err } for _, value := range ty_FileInfos { FolderList = append(FolderList, value.Name()) } return FolderList, nil } func fc_GetFolderList(FilePathInput string) (FolderList []string, err error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return FolderList, err } ty_FileInfos, err := pty_OpenFile.Readdir(-1) pty_OpenFile.Close() if err != nil { return FolderList, err } for _, value := range ty_FileInfos { if value.IsDir(){ FolderList = append(FolderList, value.Name()) } } return FolderList, nil } func fc_GetFileList(FilePathInput string) (FolderList []string, err error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return FolderList, err } ty_FileInfos, err := pty_OpenFile.Readdir(-1) pty_OpenFile.Close() if err != nil { return FolderList, err } for _, value := range ty_FileInfos { if !value.IsDir(){ FolderList = append(FolderList, value.Name()) } } return FolderList, nil } func fc_FileMove(FilePathInput, FilePathOutput string) error { return os.Rename(FilePathInput, FilePathOutput) } func fc_SetEnv(EnvVarName, EnvVarValue string) error { return os.Setenv(EnvVarName, EnvVarValue) } func fc_IsFileModeCode(vs_chmod string) bool { if len(vs_chmod) == 3 || len(vs_chmod) == 4 { _, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) if err_chmodCheck == nil { for _, value := range vs_chmod { if value == '8' || value == '9' { return false } } return true } } return false } func fc_FileModeEnCode(vs_chmod string) (vs_ModeCodestring string, err error) { switch len(vs_chmod) { case 1: //r、w表示同時適用OWNER(Windows,Unix) switch vs_chmod { case "r": return "0200", nil case "w": return "0400", nil } case 2: //rw兩字表示同時適用OWNER(Windows,Unix) if vs_chmod == "rx" || vs_chmod == "xr" { return "0200", nil } else if vs_chmod == "wx" || vs_chmod == "xw" { return "0400", nil } else if vs_chmod == "rw" || vs_chmod == "wr" { return "0600", nil } case 3: //rwx三字表示同時適用OWNER(Windows,Unix),777三數字僅適用Unix switch vs_chmod { case "rwx", "rxw", "xrw", "xwr", "wrx", "wxr": return "0700", nil default: if fc_IsFileModeCode(vs_chmod) { return "0" + vs_chmod, nil } } case 4: if fc_IsFileModeCode(vs_chmod) { return vs_chmod, nil } case 9: var vu_ower, vu_group, vu_others, vu_sum uint64 for index, value := range vs_chmod { switch value { case 'r': vu_sum = vu_sum + 4 case 'w': vu_sum = vu_sum + 2 case 'x': vu_sum = vu_sum + 1 case '-': continue default: return "", errors.New("Bad chmod input") } switch index { case 2: vu_ower = vu_sum vu_sum = 0 case 5: vu_group = vu_sum vu_sum = 0 case 8: vu_others = vu_sum case 9: return "", errors.New("Bad chmod input") } } if vu_ower > 7 || vu_group > 7 || vu_others > 7 { return "", errors.New("Bad chmod input") } else { return "0" + strconv.FormatUint(vu_ower, 10) + strconv.FormatUint(vu_group, 10) + strconv.FormatUint(vu_others, 10), nil } } return "", errors.New("Bad chmod input") } func fc_IsExist(FilePathInput string) bool { if _, err := os.Stat(FilePathInput); os.IsExist(err) { return false } return true } func fc_IsNotExist(FilePathInput string) bool { if _, err := os.Stat(FilePathInput); os.IsNotExist(err) { return true } return false } func fc_CreatFile(FilePathInput string) error { _, err := os.Create(FilePathInput) //666 return err } func fc_CreatFolder(FilePathInput, vs_chmod string) error { var err error if vs_chmod == "" { err = os.MkdirAll(FilePathInput, 0777) return err } vu_chmodNum, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) if err_chmodCheck != nil { err = os.MkdirAll(FilePathInput, 0777) } else { err = os.MkdirAll(FilePathInput, os.FileMode(vu_chmodNum)) } return err } func fc_RemovePath(FilePathInput string) error { err := os.RemoveAll(FilePathInput) return err } func fc_RemoveFile(FilePathInput string) error { ty_FileStat, err := os.Stat(FilePathInput) if !ty_FileStat.IsDir() { err = os.Remove(FilePathInput) return err } else { return errors.New("It's a Folder not File") } } func fc_RemoveFolder(FilePathInput string) error { ty_FileStat, err := os.Stat(FilePathInput) if ty_FileStat.IsDir() { err = os.Remove(FilePathInput) return err } else { return errors.New("It's a File not Empty-Folder") } } func fc_ReadFile(FilePathInput string) (string, error) { sl_Output, err := ioutil.ReadFile(FilePathInput) if err != nil { return "", err } else { return string(sl_Output), nil } } func fc_ReadBufFile(FilePathInput string, BufSize int64) (string, error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return "", err } defer pty_OpenFile.Close() pty_BufReader := bufio.NewReader(pty_OpenFile) sl_Output := make([]byte, BufSize) _, err = pty_BufReader.Read(sl_Output) if err != nil { return "", err } else { return string(sl_Output), nil } } func fc_ClearFile(FilePathInput string) error { _, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_TRUNC, 0222) return err } func fc_AppendFile(FilePathInput string, WriteString string) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) if err != nil { return err } defer pty_OpenFile.Close() pty_NewWriter := bufio.NewWriter(pty_OpenFile) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_AppendBufFile(FilePathInput string, WriteString string, vi_Bufsize int) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) if err != nil { return err } defer pty_OpenFile.Close() //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_WriteNewFile(FilePathInput string, WriteString string) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) if err != nil { return err } defer pty_OpenFile.Close() pty_NewWriter := bufio.NewWriter(pty_OpenFile) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_WriteBufNewFile(FilePathInput string, WriteString string, vi_Bufsize int) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) if err != nil { return err } defer pty_OpenFile.Close() //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_UrlDownload(SavePathInput string, UrlInput string) error { // Get the data pty_HttpRESP, err := http.Get(UrlInput) if err != nil { return err } defer pty_HttpRESP.Body.Close() // Create the file pty_FileOut, err := os.Create(SavePathInput) if err != nil { return err } defer pty_FileOut.Close() // Write the body to file _, err = io.Copy(pty_FileOut, pty_HttpRESP.Body) return err }
FileMode:
函式名稱 說明 O_RDONLY 只讀模式打開文件 O_WRONLY 只寫模式打開文件 O_RDWR 讀寫模式打開文件 O_APPEND 寫操作時將數據附加到文件尾部 O_CREAT 如果不存在將創建一個新文件 O_EXCL 和O_CREATE配合使用,文件必須不存在 O_SYNC 打開文件用於同步I/O O_TRUNC 如果可能,打開時清空文件
package main import ( "flag" "fmt" "os" ) func main() { //os.Args為string切片類型 fmt.Printf("一共接收到: %v 個參數 (%T)\n", len(os.Args), os.Args) for index, value := range os.Args { fmt.Printf("os.Args[%v]=%v\n", index, value) } //os.Args命令列參數具備次序性 fmt.Println() fmt.Println() //////////////////////////////// var user string var pwd string var port int flag.StringVar(&user, "u", "預設用戶名", "用戶名") flag.StringVar(&pwd, "pwd", "", "密碼") flag.IntVar(&port, "port", 0, "Port") flag.Parse() //flag解析命令列參數 fmt.Printf("User=%v\nPwd=%v\nPort=%v\n", user, pwd, port) // cmd.exe -u 123 -pwd "密碼測試" -port 00 // 一共接收到: 7 個參數 ([]string) // os.Args[0]=cmd.exe // os.Args[1]=-u // os.Args[2]=123 // os.Args[3]=-pwd // os.Args[4]=密碼測試 // os.Args[5]=-port // os.Args[6]=00 // User=123 // Pwd=密碼測試 // Port=0 }
json.Marshal
package main import ( "encoding/json" "fmt" ) func main() { ////////////////////////////////////////////////////////////////// // 將結構體輸出成json格式 type stMonster struct { Name string //json包輸入變數必須大寫 Age int Weight float64 } var oMonster = stMonster{ Name: "名稱", Age: 99, } vData, err := json.Marshal(&oMonster) if err != nil { fmt.Printf("json.Marshal錯誤 : %v\n", err) } else { fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) } // json.Marshal解析結果 : {"Name":"名稱","Age":99,"Weight":0} ///////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // 將結構體輸出成json格式 type stMonsterJ struct { Name string `json:"json名稱"` Age int `json:"json年齡"` Weight float64 `json:"json重量"` } var oMonsterJ = stMonsterJ{ Name: "JJJJ", Age: 00, Weight: 0.0, } vData, err = json.Marshal(&oMonsterJ) if err != nil { fmt.Printf("json.Marshal錯誤 : %v\n", err) } else { fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) } //json.Marshal解析結果 : {"json名稱":"JJJJ","json年齡":0,"json重量":0} ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// // 將map輸出成json格式 var mData map[string]interface{} mData = make(map[string]interface{}) mData["Name"] = "名稱測試" mData["Age"] = 18 mData["Weight"] = 99.0 vData, err = json.Marshal(&mData) if err != nil { fmt.Printf("json.Marshal錯誤 : %v\n", err) } else { fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) } //json.Marshal解析結果 : {"Age":18,"Name":"名稱測試","Weight":99} ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// // 將切片加入空接口並寫入map元素輸出成json格式 var sSlice []map[string]interface{} var mData1 map[string]interface{} mData1 = make(map[string]interface{}) mData1["Name"] = "名稱測試" mData1["Age"] = 18 mData1["Weight"] = 99.0 var mData2 map[string]interface{} mData2 = make(map[string]interface{}) mData2["Name"] = "名稱測試" mData2["Age"] = 18 mData2["Weight"] = 99.0 sSlice = append(sSlice, mData1, mData2) vData, err = json.Marshal(sSlice) if err != nil { fmt.Printf("json.Marshal錯誤 : %v\n", err) } else { fmt.Printf("json.Marshal解析結果 : %v\n", string(vData)) } //json.Marshal解析結果 : [{"Age":18,"Name":"名稱測試","Weight":99},{"Age":18,"Name":"名稱測試","Weight":99}] ///////////////////////////////////////////////////////////////// }
json.Unmarshal
package main import ( "encoding/json" "fmt" ) func main() { var err error sSlice := []byte(`{"Name":"柏崎星奈","Age":16,"Married":false}`) // interface 可以接收任何類型的值 var mMap map[string]interface{} err = json.Unmarshal(sSlice, &mMap) //Unmarshal只能接收 if err != nil { panic(err) } fmt.Println("Name: ", mMap["Name"]) fmt.Println("Age: ", mMap["Age"]) fmt.Printf("Married: %v\n", mMap["Married"].(bool)) // interface 也可以直接轉成你要的型別 fmt.Println() // Name: 柏崎星奈 // Age: 16 // Married: false type Identification struct { Phone string `json:"JPhone"` Email string `json:"JEmail"` } type User struct { ID int Name string Skills []string Relationship map[string]string Identification Identification } var sJsonBlob = []byte(`{"錯誤":"雜訊","Name":"人員名稱","Skills":["玩","運動"],"Relationship":{"Dad":"Hulk","Mon":"Natasha"},"Identification":{"JPhone":"cc@cc.com","JEmail":false}}`) var stUser User err = json.Unmarshal(sJsonBlob, &stUser) if err != nil { fmt.Println("error:", err) } fmt.Printf("%+v", stUser) fmt.Println() // error: json: cannot unmarshal bool into Go struct field Identification.JEmail of type string //該錯誤為 "JEmail":false 所產生 // {ID:0 Name:人員名稱 Skills:[玩 運動] Relationship:map[Dad:Hulk Mon:Natasha] Identification:{Phone:cc@cc.com Email:}} // 多餘的切片元素將會被json.Unmarshal棄置 }
go get github.com/codegangsta/inject
package main import ( "fmt" "github.com/codegangsta/inject" ) /* github.com/codegangsta/inject 利用反射(reflect)包所設計, 可將自動將變數注入到func和struct中,實現變數自動排列輸入 */ type TY_S1 interface{} type TY_S2 interface{} type Ty_Staff struct { Name string `inject` Company TY_S1 `inject` Level TY_S2 `inject` Age int `inject` } func FC_PrintData(vs_name string, if_company TY_S1, if_level TY_S2, vi_age int) { fmt.Printf("name=%s, company=%s, level=%s, age=%d\n", vs_name, if_company, if_level, vi_age) } func main() { InjectNew := inject.New() InjectNew.Map("姓名") InjectNew.MapTo("公司名稱", (*TY_S1)(nil)) InjectNew.MapTo("職稱", (*TY_S2)(nil)) InjectNew.Map(23) InjectNew.Invoke(FC_PrintData) //name=姓名, company=公司名稱, level=職稱, age=99 st_Staff := Ty_Staff{} InjectNew.Apply(&st_Staff) fmt.Printf("%v\n", st_Staff) //{XX 公司名稱 職稱 99} println() ///////////////////////////////////////////////////////////////////////////////////////////////////////// InjectNewE := inject.New() InjectNewE.Map("姓名") InjectNewE.MapTo("公司名稱", (*TY_S1)(nil)) InjectNewE.MapTo("職稱", (*TY_S2)(nil)) InjectNewE.Map(23) InjectNewE.Map("覆寫姓名") InjectNewE.MapTo("覆寫公司名稱", (*TY_S1)(nil)) InjectNewE.MapTo("覆寫職稱", (*TY_S2)(nil)) InjectNewE.Map(99) InjectNewE.Map(11.11) //多餘資料 InjectNewE.Invoke(FC_PrintData) //name=覆寫姓名, company=覆寫公司名稱, level=覆寫職稱, age=99 st_StaffE := Ty_Staff{} InjectNewE.Apply(&st_StaffE) fmt.Printf("%v\n", st_StaffE) //{覆寫姓名 覆寫公司名稱 覆寫職稱 99} }
server.go
package main import ( "log" "net" "net/http" "net/rpc" ) type Item struct { Title string Body string } type API int var database []Item func (a *API) GetDB(empty string, reply *[]Item) error { *reply = database return nil } func (a *API) GetByName(title string, reply *Item) error { var getItem Item for _, val := range database { if val.Title == title { getItem = val } } *reply = getItem return nil } func (a *API) AddItem(item Item, reply *Item) error { database = append(database, item) *reply = item return nil } func (a *API) EditItem(item Item, reply *Item) error { var changed Item for idx, val := range database { if val.Title == item.Title { database[idx] = Item{item.Title, item.Body} changed = database[idx] } } *reply = changed return nil } func (a *API) DeleteItem(item Item, reply *Item) error { var del Item for idx, val := range database { if val.Title == item.Title && val.Body == item.Body { database = append(database[:idx], database[idx+1:]...) del = item break } } *reply = del return nil } func main() { api := new(API) err := rpc.Register(api) if err != nil { log.Fatal("error registering API", err) } rpc.HandleHTTP() listener, err := net.Listen("tcp", ":4040") if err != nil { log.Fatal("Listener error", err) } log.Printf("serving rpc on port %d", 4040) http.Serve(listener, nil) if err != nil { log.Fatal("error serving: ", err) } }client.go
package main import ( "fmt" "log" "net/rpc" ) type Item struct { Title string Body string } func main() { var reply Item var db []Item client, err := rpc.DialHTTP("tcp", "localhost:4040") if err != nil { log.Fatal("Connection error: ", err) } a := Item{"First", "A first item"} b := Item{"Second", "A second item"} c := Item{"Third", "A third item"} client.Call("API.AddItem", a, &reply) client.Call("API.AddItem", b, &reply) client.Call("API.AddItem", c, &reply) client.Call("API.GetDB", "", &db) fmt.Println("Database: ", db) client.Call("API.EditItem", Item{"Second", "A new second item"}, &reply) client.Call("API.DeleteItem", c, &reply) client.Call("API.GetDB", "", &db) fmt.Println("Database: ", db) client.Call("API.GetByName", "First", &reply) fmt.Println("first item: ", reply) }
##Golang proto套件安裝 go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
# Ubuntu安裝 curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.10.1/protoc-3.10.1-linux-x86_64.zip su unzip protoc-3.10.1-linux-x86_64.zip -d protoc3 # 移動 mv protoc3/bin/* /usr/local/bin/ mv protoc3/include/* /usr/local/include/ # 修改權限 chown [user] /usr/local/bin/protoc chown -R [user] /usr/local/include/google
## windows安裝protoc後必須另外將protoc.exe環境變數%Path%內 ## protoc-gen-go.exe必須與protoc.exe在同一資料夾 copy protoc-gen-go.exe %Path%
Golang範例:
./person.proto
:syntax="proto3"; package main; message Person { string name = 1; int32 age = 2; }
## 將person.proto生成 person.pb.go protoc --go_out=. person.proto
./person.pb.go
:
// Code generated by protoc-gen-go. DO NOT EDIT. // source: person.proto package main import ( fmt "fmt" math "math" proto "github.com/golang/protobuf/proto" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type Person struct { Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"Name,omitempty"` Age int32 `protobuf:"varint,3,opt,name=age,proto3" json:"age,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *Person) Reset() { *m = Person{} } func (m *Person) String() string { return proto.CompactTextString(m) } func (*Person) ProtoMessage() {} func (*Person) Descriptor() ([]byte, []int) { return fileDescriptor_4c9e10cf24b1156d, []int{0} } func (m *Person) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Person.Unmarshal(m, b) } func (m *Person) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Person.Marshal(b, m, deterministic) } func (m *Person) XXX_Merge(src proto.Message) { xxx_messageInfo_Person.Merge(m, src) } func (m *Person) XXX_Size() int { return xxx_messageInfo_Person.Size(m) } func (m *Person) XXX_DiscardUnknown() { xxx_messageInfo_Person.DiscardUnknown(m) } var xxx_messageInfo_Person proto.InternalMessageInfo func (m *Person) GetName() string { if m != nil { return m.Name } return "" } func (m *Person) GetAge() int32 { if m != nil { return m.Age } return 0 } func init() { proto.RegisterType((*Person)(nil), "main.Person") } func init() { proto.RegisterFile("person.proto", fileDescriptor_4c9e10cf24b1156d) } var fileDescriptor_4c9e10cf24b1156d = []byte{ // 88 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x48, 0x2d, 0x2a, 0xce, 0xcf, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xc9, 0x4d, 0xcc, 0xcc, 0x53, 0xd2, 0xe3, 0x62, 0x0b, 0x00, 0x8b, 0x0a, 0x09, 0x71, 0xb1, 0xf8, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x02, 0x5c, 0xcc, 0x89, 0xe9, 0xa9, 0x12, 0xcc, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x20, 0x66, 0x12, 0x1b, 0x58, 0xb3, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xbc, 0xb8, 0xfe, 0x4c, 0x00, 0x00, 0x00, }
./main.go
:package main import ( "fmt" "github.com/golang/protobuf/proto" ) func main() { elliot := &Person{ Name: "Elliot", Age: 24, } sl_ProtobufExample, err := proto.Marshal(elliot) if err != nil { fmt.Println("marshaling error: ", err) } fmt.Printf("%s\n", sl_ProtobufExample) //?Elliot st_UnProtoExample := &Person{} err = proto.Unmarshal(sl_ProtobufExample, st_UnProtoExample) if err != nil { fmt.Println("unmarshaling error: ", err) } fmt.Println(st_UnProtoExample) //name:"Elliot" age:24 }
Go : 檔案系統操作:
package main import ( "bufio" "errors" "io" "io/ioutil" "net/http" "os" "strconv" ) // os.O_WRONLY: 只寫 // os.O_CREATE: 創建文件(如果文件不存在) // os.O_RDONLY: 只讀 // os.O_RDWR: 讀寫皆可 // os.O_APPEND: 尾部加入 // os.O_TRUNC: 清空(文件存在情況下) // 第三個參數設置權限控制 func fc_GetPWD() string { vs_WorkingDir, _ := os.Getwd() return vs_WorkingDir } func fc_SetPWD(FilePathInput string) error { err := os.Chdir(FilePathInput) return err } func fc_GetEnv(EnvVarName string) (EnvVarValue string) { return os.Getenv(EnvVarName) } func fc_GetAllEnv(EnvVarName string) (AllEnvVarValues []string) { return os.Environ() } func fc_GetPathList(FilePathInput string) (FolderList []string, err error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return FolderList, err } ty_FileInfos, err := pty_OpenFile.Readdir(-1) pty_OpenFile.Close() if err != nil { return FolderList, err } for _, value := range ty_FileInfos { FolderList = append(FolderList, value.Name()) } return FolderList, nil } func fc_GetFolderList(FilePathInput string) (FolderList []string, err error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return FolderList, err } ty_FileInfos, err := pty_OpenFile.Readdir(-1) pty_OpenFile.Close() if err != nil { return FolderList, err } for _, value := range ty_FileInfos { if value.IsDir(){ FolderList = append(FolderList, value.Name()) } } return FolderList, nil } func fc_GetFileList(FilePathInput string) (FolderList []string, err error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return FolderList, err } ty_FileInfos, err := pty_OpenFile.Readdir(-1) pty_OpenFile.Close() if err != nil { return FolderList, err } for _, value := range ty_FileInfos { if !value.IsDir(){ FolderList = append(FolderList, value.Name()) } } return FolderList, nil } func fc_FileMove(FilePathInput, FilePathOutput string) error { return os.Rename(FilePathInput, FilePathOutput) } func fc_SetEnv(EnvVarName, EnvVarValue string) error { return os.Setenv(EnvVarName, EnvVarValue) } func fc_IsFileModeCode(vs_chmod string) bool { if len(vs_chmod) == 3 || len(vs_chmod) == 4 { _, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) if err_chmodCheck == nil { for _, value := range vs_chmod { if value == '8' || value == '9' { return false } } return true } } return false } func fc_FileModeEnCode(vs_chmod string) (vs_ModeCodestring string, err error) { switch len(vs_chmod) { case 1: //r、w表示同時適用OWNER(Windows,Unix) switch vs_chmod { case "r": return "0200", nil case "w": return "0400", nil } case 2: //rw兩字表示同時適用OWNER(Windows,Unix) if vs_chmod == "rx" || vs_chmod == "xr" { return "0200", nil } else if vs_chmod == "wx" || vs_chmod == "xw" { return "0400", nil } else if vs_chmod == "rw" || vs_chmod == "wr" { return "0600", nil } case 3: //rwx三字表示同時適用OWNER(Windows,Unix),777三數字僅適用Unix switch vs_chmod { case "rwx", "rxw", "xrw", "xwr", "wrx", "wxr": return "0700", nil default: if fc_IsFileModeCode(vs_chmod) { return "0" + vs_chmod, nil } } case 4: if fc_IsFileModeCode(vs_chmod) { return vs_chmod, nil } case 9: var vu_ower, vu_group, vu_others, vu_sum uint64 for index, value := range vs_chmod { switch value { case 'r': vu_sum = vu_sum + 4 case 'w': vu_sum = vu_sum + 2 case 'x': vu_sum = vu_sum + 1 case '-': continue default: return "", errors.New("Bad chmod input") } switch index { case 2: vu_ower = vu_sum vu_sum = 0 case 5: vu_group = vu_sum vu_sum = 0 case 8: vu_others = vu_sum case 9: return "", errors.New("Bad chmod input") } } if vu_ower > 7 || vu_group > 7 || vu_others > 7 { return "", errors.New("Bad chmod input") } else { return "0" + strconv.FormatUint(vu_ower, 10) + strconv.FormatUint(vu_group, 10) + strconv.FormatUint(vu_others, 10), nil } } return "", errors.New("Bad chmod input") } func fc_IsExist(FilePathInput string) bool { if _, err := os.Stat(FilePathInput); os.IsExist(err) { return false } return true } func fc_IsNotExist(FilePathInput string) bool { if _, err := os.Stat(FilePathInput); os.IsNotExist(err) { return true } return false } func fc_CreatFile(FilePathInput string) error { _, err := os.Create(FilePathInput) //666 return err } func fc_CreatFolder(FilePathInput, vs_chmod string) error { var err error if vs_chmod == "" { err = os.MkdirAll(FilePathInput, 0777) return err } vu_chmodNum, err_chmodCheck := strconv.ParseUint(vs_chmod, 10, 32) if err_chmodCheck != nil { err = os.MkdirAll(FilePathInput, 0777) } else { err = os.MkdirAll(FilePathInput, os.FileMode(vu_chmodNum)) } return err } func fc_RemovePath(FilePathInput string) error { err := os.RemoveAll(FilePathInput) return err } func fc_RemoveFile(FilePathInput string) error { ty_FileStat, err := os.Stat(FilePathInput) if !ty_FileStat.IsDir() { err = os.Remove(FilePathInput) return err } else { return errors.New("It's a Folder not File") } } func fc_RemoveFolder(FilePathInput string) error { ty_FileStat, err := os.Stat(FilePathInput) if ty_FileStat.IsDir() { err = os.Remove(FilePathInput) return err } else { return errors.New("It's a File not Empty-Folder") } } func fc_ReadFile(FilePathInput string) (string, error) { sl_Output, err := ioutil.ReadFile(FilePathInput) if err != nil { return "", err } else { return string(sl_Output), nil } } func fc_ReadBufFile(FilePathInput string, BufSize int64) (string, error) { pty_OpenFile, err := os.Open(FilePathInput) if err != nil { return "", err } defer pty_OpenFile.Close() pty_BufReader := bufio.NewReader(pty_OpenFile) sl_Output := make([]byte, BufSize) _, err = pty_BufReader.Read(sl_Output) if err != nil { return "", err } else { return string(sl_Output), nil } } func fc_ClearFile(FilePathInput string) error { _, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_TRUNC, 0222) return err } func fc_AppendFile(FilePathInput string, WriteString string) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) if err != nil { return err } defer pty_OpenFile.Close() pty_NewWriter := bufio.NewWriter(pty_OpenFile) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_AppendBufFile(FilePathInput string, WriteString string, vi_Bufsize int) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_WRONLY|os.O_APPEND, 0222) if err != nil { return err } defer pty_OpenFile.Close() //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_WriteNewFile(FilePathInput string, WriteString string) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) if err != nil { return err } defer pty_OpenFile.Close() pty_NewWriter := bufio.NewWriter(pty_OpenFile) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_WriteBufNewFile(FilePathInput string, WriteString string, vi_Bufsize int) error { pty_OpenFile, err := os.OpenFile(FilePathInput, os.O_CREATE|os.O_RDWR, 0222) if err != nil { return err } defer pty_OpenFile.Close() //使用NewWriter方法返回的io.Writer緩衝預設大小為4096,也可以使用NewWriterSize方法設定快取的大小 pty_NewWriter := bufio.NewWriterSize(pty_OpenFile, vi_Bufsize) //將檔案寫入快取 if _, err = pty_NewWriter.WriteString(WriteString); err != nil { return err } //從快取寫入到檔案中 if err = pty_NewWriter.Flush(); err != nil { return err } else { return nil } } func fc_UrlDownload(SavePathInput string, UrlInput string) error { // Get the data pty_HttpRESP, err := http.Get(UrlInput) if err != nil { return err } defer pty_HttpRESP.Body.Close() // Create the file pty_FileOut, err := os.Create(SavePathInput) if err != nil { return err } defer pty_FileOut.Close() // Write the body to file _, err = io.Copy(pty_FileOut, pty_HttpRESP.Body) return err }
package main import "fmt" func main() { someVar := "----- start test -----" emptyVar := "" Catcher(func(panicErr interface{}) { fmt.Printf("something error : \n%v\n", panicErr) }, func() { fmt.Println(someVar) //panic("自定義錯誤") fmt.Println(emptyVar[0]) }) fmt.Println("----- still running -----") // Try func active // ----- start test ----- // something error : // runtime error: index out of range // ----- still running ----- } func Catcher(handler func(interface{}), run func()) { defer func() { if err := recover(); err != nil { handler(err) } }() fmt.Println("Try func active") run() }
package main import ( "bytes" "encoding/json" "errors" "fmt" "io/ioutil" "log" "os" "golang.org/x/net/context" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/sheets/v4" ) const ( googleAppCredentials = "./license/credentials.json" googleAccountToken = "./license/token.json" googleErrorTitle = "Google Sheet API 預期錯誤" ) func main() { credentials, err := ioutil.ReadFile(googleAppCredentials) if err != nil { log.Fatalf("Unable to read client secret file: %v\n", err) //https://developers.google.com/sheets/api/quickstart/go 需要開啟獲取app 使用google api許可 } token, err := ioutil.ReadFile(googleAccountToken) if err != nil { log.Printf("Unable to read client secret file: %v\n", err) var getGSService GoogleSheet token, err = getGSService.CreatAccTokenFromWeb(credentials, googleAccountToken, false) if err != nil { log.Fatalf("Unable to save oauth token: \n %s (%v)\n", credentials, err) } } else { var js map[string]interface{} //空interface可以容許json格式多餘換行,較人性化 if json.Unmarshal(token, &js) != nil { log.Fatalf("INVALID json: %v\n%v", err, token) //log.Printf("INVALID json: %v\n%v\n進行重新獲取Token>>>>>\n", err, token) } } // var gs1 GoogleSheet // gs1.SetService(credentials, token, "1OQmB9EOXTw07nytdlQeEtvhmREn2-koSc5rlIhNLHHc", false) // values, err := gs1.Read("Table!A2:B9") // if err != nil { // log.Fatalf("Unable to retrieve data from sheet: %v\n", err) // } // fmt.Println(values) // var writeValues [][]interface{} // xx := []interface{}{ // 0, 1, 2, 3, 4, 5, // 10, 11, 12, 13, 14, 15, // 20, 21, 22, 23, 24, 25, // 30, 31, 32, 33, 34, 35, // } // writeValues = append(writeValues, xx) // err = gs1.Clear("Table!C8:C9") // if err != nil { // log.Fatalf("Unable to retrieve data from sheet: %v\n", err) // } // var updateValues [][]interface{} // row := []interface{}{"BBB", "CCC", "DDD"} // updateValues = append(updateValues, row) // err = gs1.Update("Table!C3", updateValues) // if err != nil { // log.Fatal(err) // } var gs1 GoogleSheet gs1.SetService(credentials, token, "1OQmB9EOXTw07nytdlQeEtvhmREn2-koSc5rlIhNLHHc", false) //gs1.SheetCopy("1OQmB9EOXTw07nytdlQeEtvhmREn2-koSc5rlIhNLHHc", 210732483, "161anr6Guf9Mdmcz--10bb9G62aEEgbjQGJjzJXMqVRY") gs1.CopyFromSheet("161anr6Guf9Mdmcz--10bb9G62aEEgbjQGJjzJXMqVRY", 2014644818, "test") //fmt.Println(gs1.GetSheetGID("「Monthly Rates」的副本")) //gs1.SheetRename(1791097333,"測試!!!!!!!!!!!!!!") } type GoogleSheet struct { Srv *sheets.Service Ctx context.Context AppCredentials []byte //程式本身許可license AccToken []byte //google帳戶license SpreadSheetID string //預設google Sheet ID (由網址url取得) } //獲取google API 控制權限設定(綁定method) func (gs *GoogleSheet) getGoogleAPIConfig(appCredentials []byte, setReadOnly bool) (config *oauth2.Config, err error) { // https://developers.google.com/sheets/api/guides/authorizing 選擇api控制google帳號權限 // https://www.googleapis.com/auth/spreadsheets.readonly Allows read-only access to the user's sheets and their properties. // https://www.googleapis.com/auth/spreadsheets Allows read/write access to the user's sheets and their properties. // https://www.googleapis.com/auth/drive.readonly Allows read-only access to the user's file metadata and file content. // https://www.googleapis.com/auth/drive.file Per-file access to files created or opened by the app. // https://www.googleapis.com/auth/drive var scopeUrl string if setReadOnly { scopeUrl = sheets.SpreadsheetsReadonlyScope } else { scopeUrl = sheets.SpreadsheetsScope } config, err = google.ConfigFromJSON(appCredentials, scopeUrl) if err != nil { //log.Printf("Unable to parse client secret file to config: %v\n", err) return nil, errors.New(googleErrorTitle + ": AppCredentials 內容格式錯誤 !") } return config, nil } func (gs *GoogleSheet) GetSheetGID(sheetName string) (int64, error) { sheetService, err := gs.Srv.Spreadsheets.Get(gs.SpreadSheetID).Do() if err != nil { return 0, errors.New(googleErrorTitle + ": 「" + gs.SpreadSheetID + "」 該SheetID不存在,請檢查網址或AccountToken權限!") } for _, sheet := range sheetService.Sheets { if sheet.Properties.Title == sheetName { return sheet.Properties.SheetId, nil } } return 0, errors.New(googleErrorTitle + ": 「" + sheetName + "」 該Sheet Name不存在,請檢查Sheet內容!") } //建立Google帳戶Token File(需要瀏覽器手動操作) func (gs *GoogleSheet) CreatAccTokenFromWeb(appCredentials []byte, accTokenFilePath string, setReadOnly bool) (accToken []byte, err error) { config, err := gs.getGoogleAPIConfig(appCredentials, setReadOnly) if err != nil { //log.Printf("Unable to parse client secret file to config: %v\n", err) return nil, errors.New(googleErrorTitle + ": AppCredentials 內容格式錯誤 !") } // Request a token from the web, then returns the retrieved token. authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline) fmt.Printf("\n%v\n↑請使用瀏覽器設定你的Google帳戶,並貼入你的token authorization code ↑\n", authURL) var authCode string if _, err := fmt.Scan(&authCode); err != nil { //log.Fatalf("Unable to read authorization code: %v", err) return nil, err } tok, err := config.Exchange(context.TODO(), authCode) if err != nil { //log.Fatalf("Unable to retrieve token from web: %v", err) return nil, err } // Saves a token to a file path. fmt.Printf("已將token authorization code存入 : %s\n", accTokenFilePath) accTokenFileWrite, err := os.OpenFile(accTokenFilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { //log.Fatalf("Unable to cache oauth token: %v", err) return nil, errors.New(googleErrorTitle + ": 「" + accTokenFilePath + "」AccountToken儲存失敗!") } defer accTokenFileWrite.Close() json.NewEncoder(accTokenFileWrite).Encode(tok) gs.Ctx = context.Background() client := config.Client(gs.Ctx, tok) _, err = sheets.New(client) if err != nil { //log.Fatalf("Unable to retrieve Sheets client: %v", err) return nil, err } token, err := ioutil.ReadFile(accTokenFilePath) if err != nil { //log.Fatalf("Unable to save oauth token: %v", err) return nil, err } return []byte(token), nil } //設置Google Sheet連結服務 func (gs *GoogleSheet) SetService(appCredentials []byte, accToken []byte, spreadSheetID string, setReadOnly bool) (*sheets.Service, error) { gs.AppCredentials = appCredentials gs.AccToken = accToken gs.SpreadSheetID = spreadSheetID //預先存入docs網址方便日後存取 config, err := gs.getGoogleAPIConfig(appCredentials, setReadOnly) if err != nil { // log.Printf("Unable to parse client secret file to config: %v\n", err) return nil, errors.New(googleErrorTitle + ": AppCredentials 內容格式錯誤 !") } tok := &oauth2.Token{} err = json.NewDecoder(bytes.NewReader(gs.AccToken)).Decode(tok) if err != nil { //log.Fatalf("Unable to cache oauth token: %v", err) return nil, err } client := config.Client(context.Background(), tok) gs.Srv, err = sheets.New(client) if err != nil { //log.Printf("Unable to retrieve Sheets client: %v\n", err) return nil, err } return gs.Srv, nil } //獲取sheet中的數值 func (gs *GoogleSheet) SheetRead(readRange string) ([][]interface{}, error) { resp, err := gs.Srv.Spreadsheets.Values.Get(gs.SpreadSheetID, readRange).Do() if err != nil { return nil, err } return resp.Values, err } //寫入sheet中的數值 func (gs *GoogleSheet) SheetWrite(writeRange string, values [][]interface{}) error { valueInputOption := "RAW" requestBody := &sheets.ValueRange{ MajorDimension: "ROWS", Values: values, } _, err := gs.Srv.Spreadsheets.Values.Append(gs.SpreadSheetID, writeRange, requestBody).ValueInputOption(valueInputOption).Do() return err } //改變sheet中的數值 func (gs *GoogleSheet) SheetUpdate(updateRange string, updateValues [][]interface{}) error { valueInputOption := "RAW" requestBody := &sheets.ValueRange{ MajorDimension: "ROWS", Values: updateValues, } _, err := gs.Srv.Spreadsheets.Values.Update(gs.SpreadSheetID, updateRange, requestBody).ValueInputOption(valueInputOption).Do() return err } //清除sheet中的數值 func (gs *GoogleSheet) SheetClear(clearRange string) error { // rb has type *ClearValuesRequest requestBody := &sheets.ClearValuesRequest{} _, err := gs.Srv.Spreadsheets.Values.Clear(gs.SpreadSheetID, clearRange, requestBody).Do() return err } //操作兩Google Sheet 間作sheet複製(需要自行設置權限,並取得Sheet的gid) func (gs *GoogleSheet) CopyBetweenSheet(sourceSheetID string, sourceSheetGID int64, destSheetID string) (resp *sheets.SheetProperties, err error) { requestBody := &sheets.CopySheetToAnotherSpreadsheetRequest{ DestinationSpreadsheetId: destSheetID, } resp, err = gs.Srv.Spreadsheets.Sheets.CopyTo(sourceSheetID, sourceSheetGID, requestBody).Context(gs.Ctx).Do() return resp, err } //選擇sheetGID 並重新命名 func (gs *GoogleSheet) SheetGIDRename(sheetGID int64, newName string) (resp *sheets.BatchUpdateSpreadsheetResponse, err error) { requestBody := &sheets.BatchUpdateSpreadsheetRequest{ Requests: []*sheets.Request{&sheets.Request{ UpdateSheetProperties: &sheets.UpdateSheetPropertiesRequest{ Properties: &sheets.SheetProperties{ SheetId: sheetGID, Title: newName, }, Fields: "title", }, }}, } resp, err = gs.Srv.Spreadsheets.BatchUpdate(gs.SpreadSheetID, requestBody).Context(gs.Ctx).Do() return resp, err } //複製外部sheet到現在工作的Google Sheet(需要自行設置權限,並取得Sheet的gid) func (gs *GoogleSheet) CopyFromSheet(sourceSheetID string, sourceSheetGID int64, newName string) (resp *sheets.SheetProperties, err error) { requestBody := &sheets.CopySheetToAnotherSpreadsheetRequest{ DestinationSpreadsheetId: gs.SpreadSheetID, } resp, err = gs.Srv.Spreadsheets.Sheets.CopyTo(sourceSheetID, sourceSheetGID, requestBody).Context(gs.Ctx).Do() if newName != "" && err == nil { _, err2 := gs.SheetGIDRename(resp.SheetId, newName) if err2 != nil { err = err2 } } return resp, err }
Server端:
package main import ( "fmt" "log" "net" "os" "time" ) const buffSize = 1024 func main() { //建立socket,監聽埠 listenPort := ":51680" netListen, err := net.Listen("tcp", listenPort) if err != nil { log.Printf("listen tcp '%v' fail > '%v'\n", listenPort, err) os.Exit(1) } defer netListen.Close() log.Println("Waiting for clients") var clientList = make(map[*net.Conn]struct{}) go func() { //監聽採用無限制迴圈 for { conn, err := netListen.Accept() if err != nil { continue } clientIP := conn.RemoteAddr().String() log.Println(clientIP, " tcp connect success") buffer := make([]byte, buffSize) //超過緩存範圍訊息將被斷行打印 go func() { //每個客戶端開goroutine for { clientList[&conn] = struct{}{} //struct不占記憶體空間 endChr, err := conn.Read(buffer) //阻塞式,當無client連接時會進行等待 if err != nil { log.Println(clientIP, " connection error: ", err) delete(clientList, &conn) break } switch string(buffer[:endChr]) { case "bye": //關閉客戶端 conn.Write([]byte("Bye bye!")) delete(clientList, &conn) //移除廣播清單 return //關閉goroutine default: //接收客戶端訊息 log.Println(clientIP, "receive data string:") } } return }() } }() var sendMsg string for { //廣播給所有清單內的客戶端 fmt.Scanln(&sendMsg) for client, _ := range clientList { conn := *client _, err := conn.Write([]byte(sendMsg)) if err != nil { log.Println("廣播 fail : ", conn.RemoteAddr()) continue //監聽程序會負責移除斷線或異常的客戶端 } } log.Printf("廣播 : %s", sendMsg) time.Sleep(1 * time.Second) } }Client端:
package main import ( "fmt" "log" "net" "time" ) const buffSize = 1024 func main(){ socketAddr := "localhost:51680" var err error var socketServer *net.Conn //socket server公用控制器 go func(addr string) { var conn net.Conn buff := make([]byte, buffSize) for { if socketServer == nil { conn, err = net.Dial("tcp", addr) //與server進行連線 if err != nil { log.Printf("Reconnect error:%v\n", err) socketServer = nil time.Sleep(1 * time.Second) continue } else { socketServer = &conn defer conn.Close() log.Printf("Suecess to connect socket > '%v'\n", addr) } } endChr, err := conn.Read(buff) //接收server訊息 if err != nil { log.Println("Receive fail!") socketServer = nil continue } log.Printf("Received from server : %s", buff[:endChr]) } }(socketAddr) var sendMsg string for { fmt.Scanln(&sendMsg) conn := *socketServer //指向公用socket server _,err :=conn.Write([]byte(sendMsg)) if err !=nil{ log.Println("Sent fail !") socketServer = nil continue //若發送失敗接收者負責重連 } log.Printf("Send: %s", sendMsg) time.Sleep(1 * time.Second) } }
Server端:
package main import ( "fmt" "log" "net/http" "time" socketio "github.com/googollee/go-socket.io" ) const broadcastKey = "broadcast" const clientKey = "client message" func main() { server := socketio.NewServer(nil) var Clients = make(map[string]socketio.Conn) //連線中的Client清單 server.OnConnect("/", func(conn socketio.Conn) error { conn.SetContext("") log.Printf("connected: %v (url:'%v' LocalAddr:'%v' RemoteAddr:'%v' RemoteHeader:'%v')", conn.ID(),conn.URL(),conn.LocalAddr(),conn.RemoteAddr(),conn.RemoteHeader()) Clients[conn.ID()] = conn return nil }) server.OnDisconnect("/", func(conn socketio.Conn, reason string) { delete(Clients, conn.ID()) //清除廣播清單 log.Printf("%v closed : %v\n", conn.ID(), reason) }) server.OnError("/", func(conn socketio.Conn, err error) { log.Println("meet error:", err) //錯誤捕捉 }) server.OnEvent("/", clientKey, func(conn socketio.Conn, msg string) { if msg != "bye" { //當客戶端發送bye則將客戶端關閉 log.Printf("get from %v : %v \n", conn.ID(), msg) conn.Emit(clientKey, fmt.Sprintf("We have received your message : '%v'", msg)) //回傳給客戶端 } else { conn.Emit("bye !") log.Printf("force close client %v", conn.ID()) conn.Close() } }) go func(server *socketio.Server) { for { for index, value := range Clients { value.Emit(broadcastKey, "廣播") log.Printf("對%v 發出了廣播\n", index) } time.Sleep(5 * time.Second) } }(server) go server.Serve() defer server.Close() http.Handle("/socket.io/", server) http.Handle("/", http.FileServer(http.Dir("./asset"))) log.Println("Serving at localhost:51680...") log.Fatal(http.ListenAndServe(":51680", nil)) }
Client端:
package main import ( "fmt" "log" "time" socketIoClient "github.com/mofadeyunduo/go-socket.io-client" ) const broadcastKey = "broadcast" const clientKey = "client message" func main() { // options 為選用功能 // options := &socketIoClient.Options{ // Transport: "websocket", // Query: make(map[string]string), // } // options.Query["user"] = "user" // options.Query["pwd"] = "pass" var socketClient *socketIoClient.Client //socket server 連線控制器 socketHost := "http://localhost:51680" socketOptions := &socketIoClient.Options{} go func(client *socketIoClient.Client, uri string, opts *socketIoClient.Options) { //由於socket斷線後不會有任何提示,所以需要自行檢測與重連 for { if client == nil || client.Emit("ping", "") != nil { var err error client, err = socketIoClient.NewClient(uri, socketOptions) //與socket server 連線 if err != nil { client = nil //清空連線 log.Printf("Reconnect error:%v\n", err) } else { socketClient = client log.Printf("suecess to connect socket.io > '%v'\n", socketHost) client.On(broadcastKey, func(msg string) { //開啟監聽Server端廣播 log.Printf("got broadcast: '%v'\n", msg) }) client.On(clientKey, func(msg string) { //開啟監聽Server端傳訊 log.Printf("got message: '%v'\n", msg) }) } } time.Sleep(1 * time.Second) //每秒重新連線,並重新監聽 } }(socketClient, socketHost, socketOptions) var sendMsg string for { fmt.Scanln(&sendMsg) if socketClient.Emit(clientKey, sendMsg) == nil { log.Printf("sent : '%v'", sendMsg) } else { log.Println("sent fail !") } time.Sleep(1 * time.Second) //每秒重新連線,並重新監聽 } }