读写数据
读取用户的输入
最简单的办法是使用 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 语言之旅