读取控制台输入
1. fmt包:Scan 和 Sscan 开头的函数
var (
firstName, lastName, s string
i int
f float32
input = "56.12 / 5212 / Go"
format = "%f / %d / %s"
)
func main() {
fmt.Println("Please enter your full name: ")
// 1. Scanln
fmt.Scanln(&firstName, &lastName)
// 2. Scanf
// fmt.Scanf("%s %s", &firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi Chris Naegels
// 3. Sscanf
fmt.Sscanf(input, format, &f, &i, &s)
fmt.Println("From the string we read: ", f, i, s)
// 输出结果: From the string we read: 56.12 5212 Go
}
2. bufio 包: buffered reader
ReadString
ReadLine
ReadBytes
package main
import (
"fmt"
"bufio"
"os"
)
func main() {
// 1. 创建缓冲区
inputReader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter some input: ")
// 2. 从输入流中读取,直到遇到'\n',返回读取到的字符串input
input, err := inputReader.ReadString('\n')
if err == nil {
fmt.Printf("The input was: %s\n", input)
}
}
文件读写
1. 读文件 Open,ReadString
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
}
}
}
文件 -> []byte ->文件
WriteFile
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
inputFile := "out.txt"
outputFile := "out_copy.txt"
// out.txt -> []byte
buf, err := ioutil.ReadFile(inputFile)
if err != nil {
fmt.Fprintf(os.Stderr, "File Error: %s\n", err)
// panic(err.Error())
}
fmt.Printf("%s\n", string(buf))
// []byte -> out_copy.txt
err = ioutil.WriteFile(outputFile, buf, 0644) // oct, not hex
if err != nil {
panic(err.Error())
}
}
读 二进制文件
Read
buf := make([]byte, 1024)
...
n, err := inputReader.Read(buf) // 变量 n 的值表示读取到的字节数.
if (n == 0) { break}
数据是按列排列并用空格分隔的
Fscanln
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("out.txt")
if err != nil {
panic(err)
}
defer file.Close()
var col1, col2, col3 []string
for {
var v1, v2, v3 string
_, err := fmt.Fscanln(file, &v1, &v2, &v3)
// scans until newline
if err != nil {
break
}
col1 = append(col1, v1)
col2 = append(col2, v2)
col3 = append(col3, v3)
}
fmt.Println(col1) // 第一列
fmt.Println(col2) // 第二列
fmt.Println(col3)
}
compress包:读取压缩文件
支持的压缩文件格式为:bzip2、flate、gzip、lzw 和 zlib。
package main
import (
"fmt"
"bufio"
"os"
"compress/gzip"
)
func main() {
fName := "MyFile.gz"
var r *bufio.Reader
fi, err := os.Open(fName)
if err != nil {
fmt.Fprintf(os.Stderr, "%v, Can't open %s: error: %s\n", os.Args[0], fName,
err)
os.Exit(1)
}
defer fi.Close()
fz, err := gzip.NewReader(fi)
if err != nil {
r = bufio.NewReader(fi)
} else {
r = bufio.NewReader(fz)
}
for {
line, err := r.ReadString('\n')
if err != nil {
fmt.Println("Done reading file")
os.Exit(0)
}
fmt.Println(line)
}
}
2. 写文件 OpenFile,WriteString
package main
import (
"os"
"bufio"
"fmt"
)
func main () {
// var outputWriter *bufio.Writer
// var outputFile *os.File
// var outputError os.Error
// var outputString string
outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)
if outputError != nil {
fmt.Printf("An error occurred with file opening or creation\n")
return
}
defer outputFile.Close()
outputWriter := bufio.NewWriter(outputFile)
outputString := "hello world!\n"
for i:=0; i<10; i++ {
outputWriter.WriteString(outputString)
}
// 缓冲区-》文件
outputWriter.Flush()
}
OpenFile 函数有三个参数:文件名、一个或多个标志(使用逻辑运算符“|”连接),使用的文件权限。
我们通常会用到以下标志:
os.O_RDONLY:只读
os.O_WRONLY:只写
os.O_CREATE:创建:如果指定文件不存在,就创建该文件。
os.O_TRUNC:截断:如果指定文件已存在,就将该文件的长度截为0。
文件拷贝 io.Copy
// filecopy.go
package main
import (
"fmt"
"io"
"os"
)
func main() {
CopyFile("target.txt", "source.txt")
fmt.Println("Copy done!")
}
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
从命令行读取参数
os.Args 见1.2章
flag包
fmt.Fprintf()
fmt.Fprintf()
依据指定的格式向第一个参数内写入字符串,第一个参数必须实现了 io.Writer 接口。Fprintf() 能够写入任何类型,只要其实现了 Write 方法,包括 os.Stdout,文件(例如 os.File),管道,网络连接,通道等等,同样的也可以使用 bufio 包中缓冲写入
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
type Writer interface {
Write(p []byte) (n int, err error)
}
Eg:
import (
"bufio"
"fmt"
"os"
)
func main() {
// 不使用缓冲区
fmt.Fprintf(os.Stdout, "%s\n", "hello world! - unbuffered")
// 使用缓冲区
// 1. New一个缓冲区
// func NewWriter(wr io.Writer) (b *Writer)
buf := bufio.NewWriter(os.Stdout)
// 2. 写入缓冲区
fmt.Fprintf(buf, "%s\n", "hello world! - buffered")
// 3. 缓冲区输出到控制台os.Stdout
buf.Flush()
}
JSON 数据格式
序列化,编码 Marshal
// 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}:
// 1. 序列化
js, _ := json.Marshal(vc)
fmt.Printf("JSON format: %s", js)
// 2. 创建io.Writer
file, _ := os.OpenFile("vcard.json", os.O_CREATE|os.O_WRONLY, 0666)
defer file.Close()
// 3. 将数据对象vc写入io.Writer 的file里
enc := json.NewEncoder(file)
err := enc.Encode(vc)
if err != nil {
log.Println("Error in encoding json")
}
}
SON 与 Go 类型对应如下:
bool 对应 JSON 的 boolean
float64 对应 JSON 的 number
string 对应 JSON 的 string
nil 对应 JSON 的 null
不是所有的数据都可以编码为 JSON 类型:只有验证通过的数据结构才能被编码:
- JSON 对象只支持字符串类型的 key;要编码一个 Go map 类型,map 必须是 map[string]T(T是 json 包中支持的任何类型)
- Channel,复杂类型和函数类型不能被编码
- 不支持循环数据结构;它将引起序列化进入一个无限循环
- 指针可以被编码,实际上是对指针指向的值进行编码(或者指针是 nil)
反序列化 解码 Unmarshal
解析 []byte 中的 JSON 数据并将结果存入指针 &v 指向的值
func Unmarshal(data []byte, v interface{}) error
解码任意的数据:
// twitter_status_json.go
package main
import (
"encoding/json"
"fmt"
)
func main() {
// Json
b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`)
// 1. 解码结果存在空接口中
var f interface{}
err := json.Unmarshal(b, &f)
if err != nil {
fmt.Println("err")
}
// 2. f指向一个map,key = string, value = interface{}不同类型的值
// 那么可以利用类型断言,转换f的类型
m := f.(map[string]interface{})
// 3. type-switch 判断实际类型
for key, value := range m {
switch vv := value.(type) {
case string:
fmt.Println(key, "is string", vv)
case int:
fmt.Println(key, "is int", vv)
case []interface{}:
fmt.Println(key, "a array", vv)
default:
fmt.Println(key, "is of a type I don’t know how to handle",)
}
}
}
解码数据到结构:
type FamilyMember struct {
Name string
Age int
Parents []string
}
并对其反序列化:
var m FamilyMember
err := json.Unmarshal(b, &m)
编码和解码流
json 包提供 Decoder 和 Encoder 类型来支持常用 JSON 数据流读写
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
要想把 JSON 直接写入文件,可以使用 json.NewEncoder 初始化文件(或者任何实现 io.Writer 的类型),并调用 Encode();
反过来与其对应的是使用 json.NewDecoder 和 Decode() 函数:
只要是实现了Reader和Writer方法的,都可以传参到NewDecoder和NewEncoder进行Json编码解码
XML 数据格式
encoding/xml 包实现了一个简单的 XML 解析器(SAX),用来解析 XML 数据内容
<Person>
<FirstName>Laura</FirstName>
<LastName>Lynn</LastName>
</Person>
// xml.go
package main
import (
"encoding/xml"
"fmt"
"strings"
)
var t, token xml.Token
var err error
func main() {
input := "<Person><FirstName>Laura</FirstName><LastName>Lynn</LastName></Person>"
inputReader := strings.NewReader(input)
p := xml.NewDecoder(inputReader)
for t, err = p.Token(); err == nil; t, err = p.Token() {
switch token := t.(type) {
case xml.StartElement:
name := token.Name.Local
fmt.Printf("Token name: %s\n", name)
for _, attr := range token.Attr {
attrName := attr.Name.Local
attrValue := attr.Value
fmt.Printf("An attribute is: %s %s\n", attrName, attrValue)
// ...
}
case xml.EndElement:
fmt.Println("End of token")
case xml.CharData:
content := string([]byte(token))
fmt.Printf("This is the content: %v\n", content)
// ...
default:
// ...
}
}
}
包中定义了若干 XML 标签类型:StartElement,Chardata(这是从开始标签到结束标签之间的实际文本),EndElement,Comment,Directive 或 ProcInst。
用 Gob 传输数据
和 JSON 的使用方式一样,Gob 使用通用的 io.Writer 接口,通过 NewEncoder() 函数创建 Encoder 对象并调用 Encode();相反的过程使用通用的 io.Reader 接口,通过 NewDecoder() 函数创建 Decoder 对象并调用 Decode()。
以字节缓冲模拟网络传输的简单例子:
// 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) // 编码,输出到网络字节流中
dec := gob.NewDecoder(&network) // 解码
// 编码后发给network
err := enc.Encode(P{3, 4, 5, "Pythagoras"})
if err != nil {
log.Fatal("encode error:", err)
}
// 从network里取数据,解码后写进q对象
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}
对文件操作
// gob2.go
package main
import (
"encoding/gob"
"log"
"os"
"fmt"
)
type Address struct {
Type string
City string
Country string
}
type VCard struct {
FirstName string
LastName string
Addresses []*Address
Remark string
}
var content string
// 编码到文件
func encodeToFile() {
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}:
// using an encoder:
file, _ := os.OpenFile("vcard.gob", os.O_CREATE|os.O_WRONLY, 0666)
defer file.Close()
enc := gob.NewEncoder(file)
err := enc.Encode(vc)
if err != nil {
log.Println("Error in encoding gob")
}
}
// 解码到控制台输出
func decodeToCmd() {
file, _ := os.Open("vcard.gob")
defer file.Close()
var vc VCard
dec := gob.NewDecoder(file)
err := dec.Decode(&vc)
if err != nil {
fmt.Println("error")
}
fmt.Println(vc) // {Jan Kersschot [0xc00005f410 0xc00005f440] none}
}
func main() {
encodeToFile()
decodeToCmd()
}