GO语言学习笔记(与Java的比较学习)(九)

03-08 1377阅读

读写数据

读取用户的输入

最简单的办法是使用 fmt 包提供的 Scan 和 Sscan 开头的函数。

Scanln 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。Scanf 与其类似,除了 Scanf 的第一个参数用作格式字符串,用来决定如何读取。Sscan 和以 Sscan 开头的函数则是从字符串读取,除此之外,与 Scanf 相同。

GO语言学习笔记(与Java的比较学习)(九)

package main
​
import "fmt"
​
var (
    firstName, lastName, s string
    age, i                 int
    f                      float32
    input                  = "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  

JSON 数据格式

// json.go
package main
​
import (
    "encoding/json"
    "fmt"
    "log"
    "os"
)
​
type Address struct {
    Type    string
    City    string
    Country string
}
​
type VCard struct {
    FirstName string
    LastName  string
    Addresses []*Address
    Remark    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 标签中。

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 int
    Name    string
}
​
type Q struct {
    X, Y *int32
    Name 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 Q
    err = 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 语言之旅

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]