讀寫數據
讀取用戶的輸入
最簡單的辦法是使用 fmt
包提供的 Scan 和 Sscan 開頭的函數。
Scanln 掃描來自標準輸入的文本,將空格分隔的值依次存放到后續的參數內,直到碰到換行。Scanf 與其類似,除了 Scanf 的第一個參數用作格式字符串,用來決定如何讀取。Sscan 和以 Sscan 開頭的函數則是從字符串讀取,除此之外,與 Scanf 相同。
package main
?
import "fmt"
?
var (firstName, lastName, s stringage, i ? ? ? ? ? ? ? ? intf ? ? ? ? ? ? ? ? ? ? ?float32input ? ? ? ? ? ? ? ? ?= "1 / 1.1 / aa"format ? ? ? ? ? ? ? ? = "%d / %f / %s"
)
?
func main() {println("Please enter your name: ")// 使用空格符分割的輸入fmt.Scanln(&firstName, &lastName)fmt.Printf("Hi %s %s!\n", firstName, lastName)println("Please enter your age: ")// 規范輸入格式的輸入fmt.Scanf("%d", &age)fmt.Printf("your age is %d\n", age)// 讀取指定字符串的內容fmt.Sscanf(input, format, &i, &f, &s)fmt.Println("From this string we can read: ", i, f, s)
}
文件讀寫
package main
import ("bufio""fmt""io""os"
)
?
func main() {inputFile, inputError := os.Open("input.dat")if inputError != nil {fmt.Printf("An error occurred on opening the inputfile\n" +"Does the file exist?\n" +"Have you got acces to it?\n")return // exit the function on error}defer inputFile.Close()
?inputReader := bufio.NewReader(inputFile)for {inputString, readerError := inputReader.ReadString('\n')fmt.Printf("The input was: %s", inputString)if readerError == io.EOF {return} ? ? ?}
}
文件拷貝
從命令行讀取參數
os 包
os 包中有一個 string 類型的切片變量 os.Args
,用來處理一些基本的命令行參數,它在程序啟動后讀取命令行輸入的參數。
flag 包
flag 包有一個擴展功能用來解析命令行選項。
flag.Parse()
掃描參數列表(或者常量列表)并設置 flag, flag.Arg(i)
表示第 i 個參數。Parse()
之后 flag.Arg(i)
全部可用
flag.Narg()
返回參數的數量。解析后 flag 或常量就可用了。 flag.Bool()
定義了一個默認值是 false
的 flag
flag.PrintDefaults()
打印 flag 的使用幫助信息
用 buffer 讀取文件
package main
?
import ("bufio""flag""fmt""io""os"
)
?
func cat(r *bufio.Reader) {for {buf, err := r.ReadBytes('\n')if err == io.EOF {break}fmt.Fprintf(os.Stdout, "%s", buf)}return
}
?
func main() {flag.Parse()if flag.NArg() == 0 {cat(bufio.NewReader(os.Stdin))}for i := 0; i < flag.NArg(); i++ {f, err := os.Open(flag.Arg(i))if err != nil {fmt.Fprintf(os.Stderr, "%s:error reading from %s: %s\n", os.Args[0], flag.Arg(i), err.Error())continue}cat(bufio.NewReader(f))}
}
JSON 數據格式
// json.go
package main
?
import ("encoding/json""fmt""log""os"
)
?
type Address struct {Type ? ?stringCity ? ?stringCountry string
}
?
type VCard struct {FirstName stringLastName ?stringAddresses []*AddressRemark ? ?string
}
?
func main() {pa := &Address{"private", "Aartselaar", "Belgium"}wa := &Address{"work", "Boom", "Belgium"}vc := VCard{"Jan", "Kersschot", []*Address{pa, wa}, "none"}// fmt.Printf("%v: \n", vc) // {Jan Kersschot [0x126d2b80 0x126d2be0] none}:// JSON format:js, _ := json.Marshal(vc)fmt.Printf("JSON format: %s", js)// using an encoder:file, _ := os.OpenFile("vcard.json", os.O_CREATE|os.O_WRONLY, 0666)defer file.Close()enc := json.NewEncoder(file)err := enc.Encode(vc)if err != nil {log.Println("Error in encoding json")}
}
出于安全考慮,在 web 應用中最好使用 json.MarshalforHTML() 函數,其對數據執行 HTML 轉碼,所以文本可以被安全地嵌在 HTML <script> 標簽中。
json.NewEncoder() 的函數簽名是 func NewEncoder(w io.Writer) *Encoder,返回的 Encoder 類型的指針可調用方法 Encode(v interface{}),將數據對象 v 的 json 編碼寫入 io.Writer w 中。
JSON 與 Go 類型對應如下:
bool 對應 JSON 的 booleans float64 對應 JSON 的 numbers string 對應 JSON 的 strings nil 對應 JSON 的 null 不是所有的數據都可以編碼為 JSON 類型:只有驗證通過的數據結構才能被編碼:
JSON 對象只支持字符串類型的 key;要編碼一個 Go map 類型,map 必須是 map [string] T(T 是 json 包中支持的任何類型) Channel,復雜類型和函數類型不能被編碼 不支持循環數據結構;它將引起序列化進入一個無限循環 指針可以被編碼,實際上是對指針指向的值進行編碼(或者指針是 nil)
反序列化:
UnMarshal()
的函數簽名是 func Unmarshal(data []byte, v interface{}) error
把 JSON 解碼為數據結構。
上述示例中對 vc 編碼后的數據為 js ,對其解碼時,我們首先創建結構 VCard 用來保存解碼的數據:var v VCard 并調用 json.Unmarshal(js, &v),解析 [] byte 中的 JSON 數據并將結果存入指針 &v 指向的值。雖然反射能夠讓 JSON 字段去嘗試匹配目標結構字段;但是只有真正匹配上的字段才會填充數據。字段沒有匹配不會報錯,而是直接忽略掉。
編碼和解碼流
json 包提供 Decoder 和 Encoder 類型來支持常用 JSON 數據流讀寫。NewDecoder 和 NewEncoder 函數分別封裝了 io.Reader 和 io.Writer 接口。
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
要想把 JSON 直接寫入文件,可以使用 json.NewEncoder 初始化文件(或者任何實現 io.Writer 的類型),并調用 Encode ();反過來與其對應的是使用 json.Decoder 和 Decode () 函數:
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(v interface{}) error
用 Gob 傳輸數據
Gob 是 Go 自己的以二進制形式序列化和反序列化程序數據的格式;可以在 encoding 包中找到。這種格式的數據簡稱為 Gob (即 Go binary 的縮寫)。類似于 Python 的 "pickle" 和 Java 的 "Serialization"。
它和 JSON 或 XML 有什么不同呢?Gob 特定地用于純 Go 的環境中,例如,兩個用 Go 寫的服務之間的通信。這樣的話服務可以被實現得更加高效和優化。 Gob 不是可外部定義,語言無關的編碼方式。因此它的首選格式是二進制,而不是像 JSON 和 XML 那樣的文本格式。
// gob1.go
package main
?
import ("bytes""fmt""encoding/gob""log"
)
?
type P struct {X, Y, Z intName ? ?string
}
?
type Q struct {X, Y *int32Name string
}
?
func main() {// Initialize the encoder and decoder. Normally enc and dec would be ? ? ?// bound to network connections and the encoder and decoder would ? ? ?// run in different processes. ? ? ?var network bytes.Buffer ? // Stand-in for a network connection ? ? ?enc := gob.NewEncoder(&network) // Will write to network. ? ? ?dec := gob.NewDecoder(&network) // Will read from network. ? ? ?// Encode (send) the value. ? ? ?err := enc.Encode(P{3, 4, 5, "Pythagoras"})if err != nil {log.Fatal("encode error:", err)}// Decode (receive) the value. ? ? ?var q Qerr = dec.Decode(&q)if err != nil {log.Fatal("decode error:", err)}fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
}
// Output: ? "Pythagoras": {3,4}
學習參考資料:
《Go 入門指南》 | Go 技術論壇 (learnku.com)
Go 語言之旅