buffer
缓冲区 用于临时存储数据,以便更有效地进行I/O操作或其他数据处理任务。提供了很多有用的方法,实现了io.Reader、io.Writer、io.ByteWriter、io.ReaderFrom、io.WriterTo和io.Stringer接口。
创建:
NewBuffer(buf []byte),buf可选,用于指定缓冲区初识容量,默认为64字节的缓冲区
buf := bytes.NewBufferString("hello world")
fmt.Println(buf.String()) // 输出:hello world
bytes.Buffer
var buf bytes.Buffer
// 向缓冲区写入数据
buf.WriteString("Hello, ")
buf.WriteString("World!")
fmt.Println(buf.String()) // 输出:Hello, World!
写入:提供了多种写入方法,Write(字节切片)、WriteString、WriteByte、WriteRune
读取:提供了多种读取方法,Read(字节切片)、ReadString、ReadByte、ReadRune
转换:将缓冲区内容转为字符切片Bytes();转为字符串String()
截取:Truncate(n int),如果缓冲区长度超过n,则从尾部开始截取,只保留前n个字节;如果不足n,则不做操作, 报错panic: bytes.Buffer: truncation out of range。
扩容:Grow(n int),n 小于等于缓冲区的剩余容量,则不做任何操作。否则,会将缓冲区的容量扩大到原来的 2 倍或者加上 n,取两者中的较大值。扩容后的缓冲区不保证是连续的。
重置:Rest(),将缓冲区清空并重置为初识状态。
获取缓冲区未读部分长度和缓存区的总容量:Len()和Cap()
以下举🌰:
var buf bytes.Buffer
// 向缓冲区写入数据
buf.WriteString("Hello, ")
buf.Write([]byte("My name is Lily!"))、
// 转换
fmt.Print(buf.String(), "\n")
fmt.Print(buf.Bytes(), "\n") // 输出 [72 101 108 108 111 44 32 77 121 32 110 97 109 101 32 105 115 32 76 105 108 121 33]
// 长度容量
fmt.Print(buf.Len(), "\n") // 输出 23
fmt.Print(buf.Cap(), "\n") // 输出 64
// 读取
data := make([]byte, 50)
n, _ := buf.Read(data)
fmt.Print(string(data[:n]), "\n")
fmt.Print(buf.Len(), "\n") // 输出 0
fmt.Print(buf.Cap(), "\n") // 输出 64;读取后容量不变
// 截取扩容
buf.WriteString("Hello, ")
buf.Write([]byte("My name is Lily!"))
buf.Truncate(5)
fmt.Print(buf.String(), ";", buf.Len(), "\n") // 输出 Hello; 5
fmt.Print("before:", buf.Cap(), "\n") // 输出 before: 64
buf.Grow(80)
fmt.Print("after:", buf.Cap(), "\n") // 输出 after: 112
buf.Reset()
fmt.Print("Reset:", buf.String()) // 输出 Reset:
序列化和反序列化:由于 bytes.Buffer 类型支持读写操作,它可以用于序列化和反序列化结构体、JSON、XML 等数据格式。使用 encoding包(encoding/json、encoding/xml、encoding/gob 等)进行操作。举🌰JSON序列化和反序列化:
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
// 创建Person实例
p := Person{Name: "lily", Age: 18}
// 创建缓冲区存储序列化后数据
var buf bytes.Buffer
fmt.Println("before p:", p) // before p: {lily, 18}
// 序列化Person实例到缓冲区
json.NewEncoder(&buf).Encode(p)
fmt.Println("after buf:", buf.String()) // after buf: {"name":"lily","age":18}
// 创建新实例用于反序列
var p2 Person
// 反序列
json.NewDecoder(&buf).Decode(&p2)
fmt.Println("after p2:", p2) // after p2: {lily 18}
I/O
Go提供了io包,是对原始I/O操作的一系列接口。
Reader
用于读取数据。只要实现了 Read(p []byte) ,那它就是一个读取器
type Reader interface {
Read(p []byte) (n int, err error)
}
Writer
用于写入数据。只要实现了 Write(p []byte) ,那它就是一个编写器
type Writer interface {
//Write() 方法有两个返回值,一个是写入到目标资源的字节数,一个是发生错误时的错误。
Write(p []byte) (n int, err error)
}
文件相关操作
创建新文件: 返回一个文件对象
- 提供文件名创建:
Create(name string) (file *File, err Error) - 提供文件描述创建:
NewFile(fd unitptr, name string) *File
打开:
- 只读:
Open(name string) (file *File, err Error) - 可选权限打开:
OpenFile(name string, flag int, perm uint32) (file *File, err Error);flag 是打开方式(只读/读写..);perm 是权限
| 打开模式 | 说明 | 权限 | 说明 |
|---|---|---|---|
| os.O_RDONLY | 只读 | 0644 | 文件拥有者有读写权限,组和其他用户只有读权限 |
| os.O_WRONLY | 只写 | 0755 | 文件拥有者有读、写和执行权限,组和其他用户有读和执行权限。 |
| os.O_RDWR | 读写 | os.ModeDir | 表示这是一个目录。 |
| os.O_CREATE | 文件不存在,则创建它 | os.ModeAppend | 表示文件只能以追加模式打开。 |
| os.O_TRUNC | 文件已存在并且为普通文件,则将其长度截断为零 | os.FileMode | 表示文件权限的类型。你可以使用位运算符来组合多个权限。 |
| os.O_APPEND | 每次写入都添加到文件的末尾 | ||
| os.O_EXCL | 文件已存在,则返回一个错误 |
写入:
- 写入byte类型:
func (file *File) Write(b []byte) (n int, err Error) - 指定位置写入:
func (file *File) WriteAt(b []byte, off int64) (n int, err Error) - 写入String类型:
func (file *File) WriteString(s string) (ret int, err Error)
读取:
- 全部读取:
func (file *File) Read(b []byte) (n int, err Error) - 指定读取:
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
删除:func Remove(name string) Error
关闭:Close()
// 创建
file, err := os.Create("test.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 写入
file.WriteString("Hello World! My name is Lily! \n")
file.Write([]byte("I am 18"))
file.WriteAt([]byte("\n"), 12)
// 读取
b := make([]byte, 12)
n, _ := file.ReadAt(b, 12)
fmt.Println(n, string(b))
重置文件光标位置:使用Seek方法,指定一个偏移量(从文件开始处计算),以及一个基准位置(可以是文件的开始、当前位置或结束),然后移动文件的光标到那个位置。
重置到文件开头的话,以0为偏移量,以io.SeekStart为基准位置。
file, err := os.Open("test.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 读取一些数据(假设这里已经读取了一些)
// ...
// 重置文件光标到开始位置
_, err = file.Seek(0, io.SeekStart)
if err != nil {
log.Fatal(err)
}
// 现在可以从文件的开始重新读取数据了
// ..
JSON
JSON比XML更轻量级的数据交换格式,易阅读编写,易解析生成。Go内建对JSON支持,使用encoding/json可以生成和解析JSON格式的数据,遵循RFC4627协议标准。
编译成JSON格式
使用json.Marshal()对一组数据进行JSON格式编码。
// 原型
func Marshal(v interface{}) ([]byte, error)
// 🌰:
func main() {
type Person struct {
Name string
Age int64
}
person := Person{
Name: "lumi",
Age: 22,
}
p, _ := json.Marshal(person)
fmt.Println("byte:", p)
fmt.Println("jsonString", string(p))
}
// byte: [123 34 78 97 109 101 34 58 34 108 117 109 105 34 44 34 65 103 101 34 58 50 50 125]
// jsonString {"Name":"lumi","Age":22}
解码JSON数据
使用json.Unmarshal()将JSON格式文本解码为Go预期数据结构。
// 原型
func Unmarshal(data []byte, v interface{}) error
// data:[]byte类型的JSON数据
// v:目标输出容器。
// 🌰
func main() {
type Person struct {
Name string
Age int64
}
p := []byte(`{"Name":"lumi","Age":22}`)
person2 := new(Person)
err := json.Unmarshal(p, person2)
if err != nil {
fmt.Println(err)
}
fmt.Println("person2:", person2)
}
未知结构JSON解码
如果需要解码未知结构的JSON,可以将其解码结果输出到一个空接口interface{}。Go中允许用map[string]interface{}和[]interface{}到值类分别存放未知结构的JSON对象和数组。
func main() {
p := []byte(`{"Name":"lumi","Age":22}`)
var r interface{}
json.Unmarshal(p, &r)
fmt.Println("r:", r)
}
// r: map[Age:22 Name:lumi]
流式读写
encoding/json还提供Decoder和Encoder两个类型,用于支持JSON的流式写法,,并提供NewDecoder()和NewEncoder()两个函数来便于具体实现:
// 原型
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
// 🌰
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
// 解码
jsonData := `{"name":"Lumi","age":25}`
reader := strings.NewReader(jsonData)
decoder := json.NewDecoder(reader)
var person Person
err := decoder.Decode(&person)
if err != nil {
fmt.Println("JSON decoding failed:", err)
return
}
fmt.Printf("Decoded person: %+v\n", person)
// 编码
person2 := Person{Name: "Lucy", Age: 29}
encoder := json.NewEncoder(os.Stdout)
err := encoder.Encode(person2)
if err != nil {
fmt.Println("JSON encoding failed:", err)
return
}
}