「学习笔记」Golang – 读写数据
文章目录
读和写
Golang中,io包提供了用于读和写的接口io.Reader和io.Writer:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
只要类型实现了读写接口,提供Read()和Write()方法,就可以读写数据。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// unbuffered:未实现接口
fmt.Fprintf(os.Stdout, "%s\n", "hello world! - unbuffered")
// buffered: 实现了接口
buf := bufio.NewWriter(os.Stdout) // os.Stdout 实现了 io.Writer 接口
fmt.Fprintf(buf, "%s\n", "hello world! - buffered")
buf.Flush()
}
- 使用
fmt包提供的Scan和Sscan开头的函数,可以从键盘和标准输入os.Stdin读取输入。 io包里的Readers和Writers都是不带缓冲的,bufio包里提供了对应的带缓冲的操作,在读写UTF-8编码的文本文件时它们尤其有用。
inputReader := bufio.NewReader(os.Stdin)
input, err := inputReader.ReadString('\n')
文件读写
在 Go 语言中,文件使用指向 os.File 类型的指针来表示的,也叫做文件句柄。
读文件
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
inputFile, inputError := os.Open("input.dat") // inputFile 是 *os.File 类型的,只读模式打开 input.dat 文件
if inputError != nil {
fmt.Printf("An error occurred on opening the inputfile\n")
return
}
defer inputFile.Close() // 确保在程序退出前关闭该文件
inputReader := bufio.NewReader(inputFile) // 使用 bufio 包提供的读取器
for { // 无限循环
inputString, readerError := inputReader.ReadString('\n') // 将文件的内容逐行(行结束符 '\n')读取出来
fmt.Printf("The input was: %s", inputString)
if readerError == io.EOF { // 读取到文件末尾,退出循环
return
}
}
}
使用io/ioutil包里的ioutil.ReadFile()方法,可以将整个文件的内容读到一个字符串里:
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
inputFile := "products.txt"
outputFile := "products_copy.txt"
buf, err := ioutil.ReadFile(inputFile) // 返回值类型: []byte, err
if err != nil {
fmt.Fprintf(os.Stderr, "File Error: %s\n", err)
}
fmt.Printf("%s\n", string(buf))
err = ioutil.WriteFile(outputFile, buf, 0644) // oct, not hex
if err != nil {
panic(err.Error())
}
}
可以使用bufio.Reader的Read()读取二进制文件。
buf := make([]byte, 1024)
...
n, err := inputReader.Read(buf)
if (n == 0) { break}
compress包提供了读取压缩文件的功能,支持的压缩文件格式为:bzip2、flate、gzip、lzw和zlib。
写文件
package main
import (
"os"
"bufio"
"fmt"
)
func main () {
outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)// ①以只写模式打开文件 output.dat,如果文件不存在则自动创建
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() // ④将缓存的文件真正写入到文件中
}
os.OpenFile(文件名,标志,权限)参数中的标志(使用逻辑运算符 “|” 连接):os.O_RDONLY:只读os.O_WRONLY:只写os.O_CREATE:创建:如果指定文件不存在,就创建该文件。os.O_TRUNC:截断:如果指定文件已存在,就将该文件的长度截为 0。
拷贝文件
package main
import (
"fmt"
"io"
"os"
)
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName) // ①只读模式打开 srcName 文件
if err != nil {
return
}
defer src.Close()
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) // ②以只写模式打开文件dstName,如果文件不存在则自动创建
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src) // ③将src 拷贝到 dst
}
func main() {
CopyFile("target.txt", "source.txt")
fmt.Println("Copy done!")
}
编码和解码(或 序列化与反序列化)
- 数据结构要在网络中传输或保存到文件,就必须对其编码和解码;目前存在很多编码格式:
JSON,XML,gob,Google缓冲协议等等。 - 编码是输出一个数据流(实现了
io.Writer接口);解码是从一个数据流(实现了io.Reader)输出到一个数据结构。
json 包
Golang的 json 包可以让你在程序中方便的读取和写入JSON数据。
// json.go
package main
import (
"encoding/json"
"fmt"
"log"
"os"
)
type Address struct {
Type string
City string
Country string
}
type Person struct {
FirstName string
LastName string
Addresses []*Address
Remark string
}
func main() {
pa := &Address{"private", "Aartselaar", "Belgium"}
wa := &Address{"work", "Boom", "Belgium"}
vc := Person{"Jan", "Kersschot", []*Address{pa, wa}, "none"}
js, _ := json.Marshal(vc) // JSON format
fmt.Printf("JSON format: %s", js)
file, _ := os.OpenFile("person.json", os.O_CREATE|os.O_WRONLY, 0666) // Using an encoder
defer file.Close()
enc := json.NewEncoder(file)
err := enc.Encode(vc)
if err != nil {
log.Println("Error in encoding json")
}
}
json.Marshal()序列化的函数签名是func Marshal(v interface{}) ([]byte, error):把数据结构编码为JSON。- 数据编码后的
JSON文本(实际上是一个[]byte):
{
"FirstName": "Jan",
"LastName": "Kersschot",
"Addresses": [{
"Type": "private",
"City": "Aartselaar",
"Country": "Belgium"
}, {
"Type": "work",
"City": "Boom",
"Country": "Belgium"
}],
"Remark": "none"
}
JSON与Go类型对应如下:bool对应 JSON 的booleansfloat64对应 JSON 的numbersstring对应 JSON 的stringsnil对应 JSON 的null
json.UnMarshal()反序列化的函数签名是func Unmarshal(data []byte, v interface{}) error:把JSON解码为数据结构。
b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`)
var f interface{}
err := json.Unmarshal(b, &f)
用 Gob 传输数据
Gob(即Go binary的缩写)是Golang自己的以二进制形式序列化和反序列化程序数据的格式;可以在encoding包中找到。通常用于RPC调用参数和结果的传输,以及应用程序和机器之间的数据传输。
Gob文件或流是完全自描述的:里面包含的所有类型都有一个对应的描述,并且总是可以用Go解码,而不需要了解文件的内容。
package main
import (
"encoding/gob"
"log"
"os"
)
type Address struct {
Type string
City string
Country string
}
type Person struct {
FirstName string
LastName string
Addresses []*Address
Remark string
}
func main() {
pa := &Address{"private", "Aartselaar","Belgium"}
wa := &Address{"work", "Boom", "Belgium"}
vc := Person{"Jan", "Kersschot", []*Address{pa,wa}, "none"}
file, _ := os.OpenFile("person.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")
}
}
和JSON的使用方式一样,Gob使用通用的io.Writer接口,通过NewEncoder()函数创建Encoder对象并调用Encode();
相反的过程使用通用的io.Reader接口,通过NewDecoder()函数创建Decoder对象并调用Decode。
通过网络传输的数据必须加密,以防止被读取或篡改,并且保证发出的数据和收到的数据检验和一致。
Go的标准库为此提供了超过30个的包:
hash包:实现了adler32、crc32、crc64和fnv校验;crypto包:实现了其它的hash算法,比如md4、md5、sha1等。以及完整地实现了aes、blowfish、rc4、rsa、xtea等加密算法。
END .
相关系列文章
- 「学习笔记」Golang -- GoFrame框架
- 「学习笔记」Golang -- Go协程 与 通道
- 「学习笔记」Golang -- 读写数据
- 「学习笔记」Golang -- 动态类型与反射
- 「学习笔记」Golang -- 控制语句与错误处理
- 「学习笔记」Golang -- 内置数据类型
- 「学习笔记」Golang -- 基础入门