Go 读写数据

本文介绍了Go语言中如何读写数据,包括读取控制台输入、文件读写、文件拷贝、从命令行读取参数、JSON和XML数据格式的序列化与反序列化,以及使用Gob传输数据。重点讲解了fmt、bufio、os、flag和压缩包的使用,以及json和encoding/xml包在编码解码流中的应用。
摘要由CSDN通过智能技术生成

读取控制台输入

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 类型:只有验证通过的数据结构才能被编码:

  1. JSON 对象只支持字符串类型的 key;要编码一个 Go map 类型,map 必须是 map[string]T(T是 json 包中支持的任何类型)
  2. Channel,复杂类型和函数类型不能被编码
  3. 不支持循环数据结构;它将引起序列化进入一个无限循环
  4. 指针可以被编码,实际上是对指针指向的值进行编码(或者指针是 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()
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值