小言_互联网的博客

GoLang—数据存储(上)

356人阅读  评论(0)

数据存储可以分为三大类:文件存储、关系型的数据库(SQL)和非关系型的数据库(NoSQL)。本文主要讲述文件存储的实现方式。

文件存储根据不同的文件实现不同的存储方式:普通文件(如txt读写)、CSV文件、数据的序列化和持久化。

普通文件(如txt读写)

普通文件的读写可以使用os或io/ioutil包实现,两者的实现方式如下所示。

package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	// 使用ioutil的WriteFile对文件执行写入操作
	data := []byte("Hello World!\n")
	err := ioutil.WriteFile("data1.txt", data, 0644)
	if err != nil {
		 panic(err)
		}
	// 使用ioutil的ReadFile对文件执行读取操作
	read1, _ := ioutil.ReadFile("data1.txt")
	fmt.Print(string(read1))

	// 使用os的Create创建文件对象
	file1, _ := os.Create("data2.txt")
	// 使用defer,当程序执行结束将自动关闭文件对象file1
	defer file1.Close()
	// 使用文件对象file1对文件写入数据
	bytes, _ := file1.Write(data)
	fmt.Printf("Wrote %d bytes to file\n", bytes)

	// 使用os的Open打开文件data2.txt,生成文件对象file2
	file2, _ := os.Open("data2.txt")
	defer file2.Close()
	// 根据数据data的长度定义相应的数组
	read2 := make([]byte, len(data))
	// 由文件对象file2调用Read读取文件的数据内容,并将数据加载到数组read2
	bytes, _ = file2.Read(read2)
	fmt.Printf("Read %d bytes from file\n", bytes)
	fmt.Println(string(read2))
}

CSV文件

CSV 格式是一种文件格式,它可以让文本编辑器非常方便地读写由文本和数字组成的表格数据。CSV 的应用非常广泛,包括微软的 Excel 和苹果的 Numbers 在内的绝大多数电子表格程序都支持 CSV 格式,因此包括 Go 在内的很多编程语言都提供了能够生成和处理 CSV 文件数据的函数库。对 Go 语言来说,CSV 文件可以通过encoding/csv包进行操作,实现代码如下。

package main

import (
	"encoding/csv"
	"fmt"
	"os"
	"strconv"
)

type Post struct {
	Id int
	Content string
	Author string
}
func main() {
	// 创建文件posts.csv
	csvFile, err := os.Create("posts.csv")
	if err != nil {
		panic(err)
		}
	defer csvFile.Close()
	// 创建数据
	allPosts := []Post{
				Post{Id: 1, Content: "Hello World!", Author: "Sau Sheong"},
				Post{Id: 2, Content: "Bonjour Monde!", Author: "Pierre"},
				Post{Id: 3, Content: "Hola Mundo!", Author: "Pedro"},
				Post{Id: 4, Content: "Greetings Earthlings!", Author: "Sau Sheong"},}
	// 使用csv的NewWriter方法对文件csvFile进行写入操作
	writer := csv.NewWriter(csvFile)
	// 遍历allPosts的每行数据,将每行数据依次写入CSV文件
	for _, post := range allPosts {
		// 将strconv.Itoa(post.Id)转换成字符串格式
		// 变量line以数组的形式表示
		line := []string{strconv.Itoa(post.Id), post.Content, post.Author}
		// 将数组line写入CSV文件
		err := writer.Write(line)
		if err != nil {
			panic(err)
			}
		}
	// 调用Flush方法来保证缓冲区中的所有数据都已经被正确地写入文件里面
	writer.Flush()

	// ………………………………………………………………………………………分界线………………………………………………………………………………………
	
	// 打开CSV文件
	file, err := os.Open("posts.csv")
	if err != nil {
		panic(err)
		}
	defer file.Close()
	// 使用csv的NewWriter方法对文件csvFile进行读取操作
	reader := csv.NewReader(file)
	// 设置每行数据里面的字段数量
	// 如果FieldsPerRecord的值为正数,并且CSV文件里面读取出的字段数量少于这个值时,Go就会抛出一个错误。
	// 如果FieldsPerRecord的值为0,那么读取器就会将读取到的第一条记录的字段数量用作FieldsPerRecord的值。
	// 如果FieldsPerRecord的值为负数,即使在读取过程中发现数据里面缺少了某些字段,读取进程也不会被中断。
	reader.FieldsPerRecord = -1
	// 一次读取所有数据
	// 多次读取可使用Read()
	record, err := reader.ReadAll()
	if err != nil {
		panic(err)
		}
	// 将已读取的数据依次输出
	var posts []Post
	for _, item := range record {
		// 将字段Id转化为整型
		id, _ := strconv.ParseInt(item[0], 0, 0)
		post := Post{Id: int(id), Content: item[1], Author: item[2]}
		posts = append(posts, post)
		}
	fmt.Println(posts[0].Id)
	fmt.Println(posts[0].Content)
	fmt.Println(posts[0].Author)
}

数据的序列化和持久化

go的encoding/gob包用于管理由 gob 组成的流(stream),这是一种在编码器(encoder)和解码器(decoder)之间进行交换的二进制数据,这种数据原本是为序列化以及数据传输而设计的,但它也可以用于对数据进行持久化,并且为了让用户能够方便地对文件进行读写,编码器和解码器一般都会分别包裹起程序的写入器以及读取器。简单来说,go的encoding/gob包类似python的pickle模块,两者实现的功能是相同的。
但两者对比发现,encoding/gob包的使用方法却没有python的便捷,具体的使用过程如下所示。

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"io/ioutil"
)

type Post struct {
	Id int
	Content string
	Author string
}

func store(data interface{}, filename string) {
	// 定义字节缓冲区对象buffer
	// 这是拥有Read方法和Write方法的可变长度(variable-sized)字节缓冲区
	// 换句话说,bytes.Buffer既是读取器也是写入器。
	buffer := new(bytes.Buffer)
	// 对缓冲区对象buffer设置编码,生成编码器encoder
	encoder := gob.NewEncoder(buffer)
	// 将数据data写入编码器encoder(字节缓冲区对象buffer)
	err := encoder.Encode(data)
	if err != nil {
		panic(err)
	}
	// 将缓冲区对象buffer的数据内容以字节的方式写入文件,生成二进制数据文件
	err = ioutil.WriteFile(filename, buffer.Bytes(), 0600)
	if err != nil {
		panic(err)
	}
}

func load(data interface{}, filename string) {
	// 读取文件filename的数据内容
	raw, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	// 定义字节缓冲区对象buffer,并将文件内容raw加载到字节缓冲区对象buffer
	buffer := bytes.NewBuffer(raw)
	// 在字节缓冲区对象buffer设置解码器dec
	dec := gob.NewDecoder(buffer)
	// 将解码后的数据写入参数data
	err = dec.Decode(data)
	if err != nil {
		panic(err)
	}
}

func main() {
	post := Post{Id: 1, Content: "Hello World!", Author: "Sau Sheong"}
	store(post, "post1")
	var postRead Post
	load(&postRead, "post1")
	fmt.Println(postRead.Id)
}

转载:https://blog.csdn.net/HuangZhang_123/article/details/101705967
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场