当前位置: 首页 > article >正文

Go语言学习笔记(六)——标准库

文章目录

  • 一、fmt
    • 输出
      • fmt.Print
      • 格式化占位符
      • Fprint
      • Sprint
      • Errorf
    • 输入
      • fmt.Scan
      • fmt.Scanf
      • fmt.Scanln
      • fmt.Fsanf
  • 二、os
    • 权限说明
    • os.Create
    • os.Mkdir
    • os.MkdirAll
    • os.Remove
    • os.RemoveAll
    • os.Getwd
    • os.Chdir
    • os.TempDir
    • os.Rename
    • os.Chmod
    • os.Chown
    • 文件
    • 进程相关
      • Signal
    • 环境相关
  • 三、time
    • Time类型
    • 时间戳
    • Parse解析时间
    • 格式化时间
    • time.Unix()
    • 时间间隔
    • 时间计算
      • Add
      • Sub
      • Equal
      • Before
      • After
    • 定时器
  • 四、log
    • Print
    • Panic
    • Fatal
    • 日志配置
  • 五、error
  • 六、bytes
    • 常用函数
      • 转换
      • 比较
      • 清理
      • 拆合
      • 字串
      • 替换
    • Buffer类型
      • 声明buffer
      • 往Buffer中写入数据
      • 从Buffer中读取数据
      • 其他方法
    • Reader类型
  • 七、io
    • 错误变量
    • 基础接口
      • Reader接口
      • Writer接口
      • Seeker接口
      • Closer接口
    • 组合接口
      • ReadWriter接口
      • ReadCloser接口
      • WriteCloser接口
      • ReadWriteCloser接口
      • ReadSeeker接口
      • WriteSeeker接口
      • ReadWriteSeeker接口
    • 指定读写器读写接口
      • ReaderFrom接口
      • WriterTo接口
    • 指定偏移量读写接口
      • ReaderAt接口
      • WriterAt接口
    • 单个字节读写接口
      • ByteReader接口
      • ByteScanner接口
      • ByteWriter接口
      • RuneReader接口
      • RuneScanner接口
      • StringWriter接口
    • 结构体
      • LimitedReader
      • PipeReader
      • PipeWriter
      • SectionReader
    • 供外部调用的函数
      • Copy
      • CopyBuffer
      • CopyN
      • LimitReader
      • MultiReader
      • MultiWriter
      • Pipe
      • ReadAll
      • ReadAtLeast
      • ReadFull
      • SectionReader
        • NewSectionReader
        • SectionReader.Read
        • SectionReader.ReadAt
        • SectionReader.Seek
        • SectionReader.Size
      • TeeReader
      • WriteString

一、fmt

go版本:1.18.1

主要分为向外输出内容和获取输入内容两大部分

输出

fmt.Print

print 有三个相关的函数:

func Print(a ...any) (n int, err error) {
	return Fprint(os.Stdout, a...)
}
func Println(a ...any) (n int, err error) {
	return Fprintln(os.Stdout, a...)
}
func Printf(format string, a ...any) (n int, err error) {
	return Fprintf(os.Stdout, format, a...)
}

可以看到,最终调用的都是Fprintf,os.Stdout代表标准输出,即控制台输出

格式化占位符

占位符说明
%v值的默认格式表示
%+v类似%v,但输出结构体时会添加字段名
%#v值的Go语法表示
%T打印值的类型
%%百分号
type User struct {
	Id int64
}
func TestPrintf1(t *testing.T) {
	user := &User{Id: 1}
	fmt.Printf("%v\n", user)
	fmt.Printf("%+v\n", user)
	fmt.Printf("%#v\n", user)
	fmt.Printf("%T\n", user)
	fmt.Printf("%%\n")
}
占位符说明
%ttrue或false
func TestPrintf2(t *testing.T) {
	fmt.Printf("%t\n", true)
}
占位符说明
%b表示为二进制
%c该值对应的unicode码值
%d表示为十进制
%o表示为八进制
%x表示为十六进制,使用a-f
%X表示为十六进制,使用A-F
%U表示为Unicode格式:U+1234,等价于”U+%04X”
%q该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
func TestPrintf3(t *testing.T) {
	n := 180
	fmt.Printf("%b\n", n)
	fmt.Printf("%c\n", n)
	fmt.Printf("%d\n", n)
	fmt.Printf("%o\n", n)
	fmt.Printf("%x\n", n)
	fmt.Printf("%X\n", n)
	fmt.Printf("%U\n", n)
	a := 96
	fmt.Printf("%q\n", a)
	fmt.Printf("%q\n", 0x4E2D)
}
占位符说明
%b无小数部分、二进制指数的科学计数法,如-123456p-78
%e科学计数法,如-1234.456e+78
%E科学计数法,如-1234.456E+78
%f有小数部分但无指数部分,如123.456
%F等价于%f
%g根据实际情况采用%e或%f格式(以获得更简洁、准确的输出)
%G根据实际情况采用%E或%F格式(以获得更简洁、准确的输出)
func TestPrintf4(t *testing.T) {
	f := 18.54
	fmt.Printf("%b\n", f)
	fmt.Printf("%e\n", f)
	fmt.Printf("%E\n", f)
	fmt.Printf("%f\n", f)
	fmt.Printf("%F\n", f)
	fmt.Printf("%g\n", f)
	fmt.Printf("%G\n", f)
}
占位符说明
%s直接输出字符串或者[]byte
%q该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示
%x每个字节用两字符十六进制数表示(使用a-f
%X每个字节用两字符十六进制数表示(使用A-F)
func TestPrintf5(t *testing.T) {
	s := "我是字符串"
	b := []byte{65, 66, 67}
	fmt.Printf("%s\n", s)
	fmt.Printf("%s\n", b)
	fmt.Printf("%q\n", s)
	fmt.Printf("%x\n", s)
	fmt.Printf("%X\n", s)
}

占位符说明
%p表示为十六进制,并加上前导的0x

宽度通过一个紧跟在百分号后面的十进制数指定,如果未指定宽度,则表示值时除必需之外不作填充。

精度通过(可选的)宽度后跟点号后跟的十进制数指定。如果未指定精度,会使用默认精度;如果点号后没有跟数字,表示精度为0。

占位符说明
%f默认宽度,默认精度
%10f宽度9,默认精度
%.2f默认宽度,精度2
%10.2f宽度9,精度2
%10.f宽度9,精度0
占位符说明
+总是输出数值的正负号;对%q(%+q)会生成全部是ASCII字符的输出(通过转义);
空格对数值,正数前加空格而负数前加负号;对字符串采用%x或%X时(% x或% X)会给各打印的字节之间加空格
-在输出右边填充空白而不是默认的左边(即从默认的右对齐切换为左对齐);
#八进制数前加0(%#o),十六进制数前加0x(%#x)或0X(%#X),指针去掉前面的0x(%#p)对%q(%#q),对%U(%#U)会输出空格和单引号括起来的go字面值;
0使用0而不是空格填充,对于数值类型会把填充的0放在正负号后面;
func TestPrintf7(t *testing.T) {
	s := "我是字符串"
	fmt.Printf("%  d\n", 10)
	fmt.Printf("%s\n", s)
	fmt.Printf("%10s\n", s)
	fmt.Printf("%-10s\n", s)
	fmt.Printf("%10.2f\n", 10.14)
	fmt.Printf("%-10.2f\n", 10.14)
	fmt.Printf("%010s\n", s)
}

Fprint

将内容输出到一个io.Writer接口类型的变量w中。

func Fprint(w io.Writer, a ...any) (n int, err error) {
	p := newPrinter()
	p.doPrint(a)
	n, err = w.Write(p.buf)
	p.free()
	return
}
func Fprintf(w io.Writer, format string, a ...any) (n int, err error) {
	p := newPrinter()
	p.doPrintf(format, a)
	n, err = w.Write(p.buf)
	p.free()
	return
}
func Fprintln(w io.Writer, a ...any) (n int, err error) {
	p := newPrinter()
	p.doPrintln(a)
	n, err = w.Write(p.buf)
	p.free()
	return
}

n是写入的字节数量,err是返回的错误

一般用在写文件中。

func TestFPrint(t *testing.T) {
	fmt.Fprintln(os.Stdout, "向标准输出写入字符串")
}
//0表示8进制 644表示权限 os.FileMode(0777).String()进行打印
	//- rwx rwx rwx -表示普通文件
	//r表示可读
	//w表示可写
	//x表示可执行
	//第1位:文件属性,一般常用的是"-",表示是普通文件;"d"表示是一个目录。
	//第2~4位:文件所有者的权限rwx (可读/可写/可执行)。
	//第5~7位:文件所属用户组的权限rwx (可读/可写/可执行)。
	//第8~10位:其他人的权限rwx (可读/可写/可执行)。
	//在golang中,可以使用os.FileMode(perm).String()来查看权限标识:
	//os.FileMode(0777).String() //返回 -rwxrwxrwx  111 111 111
	//os.FileMode(0666).String() //返回 -rw-rw-rw-  110 110 110
	//os.FileMode(0644).String() //返回 -rw-r--r-- 
	//0777表示:创建了一个普通文件,所有人拥有所有的读、写、执行权限
	//0666表示:创建了一个普通文件,所有人拥有对该文件的读、写权限,但是都不可执行
	//0644表示:创建了一个普通文件,文件所有者对该文件有读写权限,用户组和其他人只有读权限,都没有执行权限
	s := os.FileMode(0777).String()
	fmt.Println(s)
func TestFPrint1(t *testing.T) {
	file, _ := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	fmt.Fprintln(file, "追加写入")
	file.Close()
}
package main

import (
	"fmt"
	"net/http"
)

func main() {
	//输入
	http.ListenAndServe(":8088", &MyHandler{})
}

type MyHandler struct {
}

func (*MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "我是http返回的信息")
}

Sprint

把传入的数据生成并返回一个字符串

func Sprint(a ...any) string {
	p := newPrinter()
	p.doPrint(a)
	s := string(p.buf)
	p.free()
	return s
}
func Sprintf(format string, a ...any) string {
	p := newPrinter()
	p.doPrintf(format, a)
	s := string(p.buf)
	p.free()
	return s
}
func Sprintln(a ...any) string {
	p := newPrinter()
	p.doPrintln(a)
	s := string(p.buf)
	p.free()
	return s
}
func TestSPrint(t *testing.T) {
	s1 := fmt.Sprint("张三")
	name := "张三"
	age := 18
	s2 := fmt.Sprintf("name:%s,age:%d", name, age)
	s3 := fmt.Sprintln("张三")
	fmt.Println(s1, s2, s3)
}

Errorf

根据format参数生成格式化字符串并返回一个包含该字符串的错误

func Errorf(format string, a ...any) error
func TestErrorf(t *testing.T) {
	err := fmt.Errorf("用户名格式不正确:%s", "@#¥哈哈")
	if err != nil {
		panic(err)
	}
}

输入

fmt.Scan

定义:

func Scan(a ...any) (n int, err error) {
	return Fscan(os.Stdin, a...)
}

含义:

从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符

返回值:

本函数返回成功扫描的数据个数(n)和遇到的任何错误(error)

fmt.Scanf

func Scanf(format string, a ...any) (n int, err error) {
	return Fscanf(os.Stdin, format, a...)
}

实际使用的是Fscanf

以format定义的格式来进行输入

func main() {
	var (
		name    string
		age     int
		married bool
	)
	fmt.Scanf("1:%s 2:%d 3:%t", &name, &age, &married)
	fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
}

fmt.Scanln

func Scanln(a ...any) (n int, err error) {
	return Fscanln(os.Stdin, a...)
}

func main() {
	var (
		name    string
		age     int
		married bool
	)
	fmt.Scanln(&name, &age, &married)
	fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
}

遇到回车就结束扫描

fmt.Fsanf

func Fscanf(r io.Reader, format string, a ...any) (n int, err error) {
	s, old := newScanState(r, false, false)
	n, err = s.doScanf(format, a)
	s.free(old)
	return
}
func Fscan(r io.Reader, a ...any) (n int, err error) {
	s, old := newScanState(r, true, false)
	n, err = s.doScan(a)
	s.free(old)
	return
}
func Fscanln(r io.Reader, a ...any) (n int, err error) {
	s, old := newScanState(r, false, true)
	n, err = s.doScan(a)
	s.free(old)
	return
}

将内容从一个io.Reader接口类型的变量r中读取出来,将连续的以空格分隔的值存储到由格式确定的连续的参数中

  • **r io.Reader:**此参数包含扫描的指定文本。
  • **format string:**此参数包含用于接收元素的不同格式。
  • **a …any:**此参数是每个元素的指定变量。

**返回值:**它返回成功解析的项目数和错误

二、os

os包提供了操作系统函数,但和操作系统无关。

os包的接口规定为在所有操作系统中都是一致的。

设计为Unix风格的。

权限说明

os标准库有大量的文件操作,在创建文件等操作中,需要指的perm。

在go语言中perm是一个uint32类型

在go语言中一般使用0777这样的形式进行表示。

  • 0代表是8进制

  • 777 是 - rwx rwx rwx的形式计算得出

权限项文件类型执行执行执行
字符表示(d|l|c|s|p)rwxrwxrwx
数字表示421421421
权限分配文件所有者文件所有者文件所有者文件所属组用户文件所属组用户文件所属组用户其他用户其他用户其他用户

第一位:

- : 代表这是一个普通文件(regular)
d:目录文件(directory)
l : 链接文件(link)
b: 块设备文件(block)
c: 字符设备文件(character)
s : 套接字文件(socket)
p: 管道文件(pipe)

一共有三组rwx

  • 第一组:该文件拥有者的权限
  • 第二组:该文件拥有者所在组的其他成员对该文件的操作权限
  • 第三组:其他用户组的成员对该文件的操作权限

计算过程如下:

rwxrwxrwx
111111111
777

go中的FileMode定义

type FileMode uint32

FileMode代表文件的模式和权限位。这些字位在所有的操作系统都有相同的含义,因此文件的信息可以在不同的操作系统之间安全的移植。不是所有的位都能用于所有的系统,唯一共有的是用于表示目录的ModeDir位。

const (
    // 单字符是被String方法用于格式化的属性缩写。
    ModeDir        FileMode = 1 << (32 - 1 - iota) // d: 目录
    ModeAppend                                     // a: 只能写入,且只能写入到末尾
    ModeExclusive                                  // l: 用于执行
    ModeTemporary                                  // T: 临时文件(非备份文件)
    ModeSymlink                                    // L: 符号链接(不是快捷方式文件)
    ModeDevice                                     // D: 设备
    ModeNamedPipe                                  // p: 命名管道(FIFO)
    ModeSocket                                     // S: Unix域socket
    ModeSetuid                                     // u: 表示文件具有其创建者用户id权限
    ModeSetgid                                     // g: 表示文件具有其创建者组id的权限
    ModeCharDevice                                 // c: 字符设备,需已设置ModeDevice
    ModeSticky                                     // t: 只有root/创建者能删除/移动文件
    // 覆盖所有类型位(用于通过&获取类型位),对普通文件,所有这些位都不应被设置
    ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
    ModePerm FileMode = 0777 // 覆盖所有Unix权限位(用于通过&获取类型位)
)

这些被定义的位是FileMode最重要的位。另外9个不重要的位为标准Unix rwxrwxrwx权限(任何人都可读、写、运行)。这些(重要)位的值应被视为公共API的一部分,可能会用于线路协议或硬盘标识:它们不能被修改,但可以添加新的位。

os.Create

func Create(name string) (file *File, err error)

Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会截断它(为空文件)。如果成功,返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。

如果出错,错误底层类型是*PathError

os.Mkdir

创建单个目录

func Mkdir(name string, perm FileMode) error {}

os.MkdirAll

创建多级目录

func MkdirAll(path string, perm FileMode) error {}
func mkdirAll() {
    err := os.MkdirAll("test/one/two", os.ModePerm)
    if err != nil {
        fmt.Printf("err: %v\n", err)
    }
}

os.Remove

删除一个空的目录或一个文件

func Remove(name string) error {}
func removeFile() {
	err := os.Remove("test.txt")
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
}
func removeDir() {
	err := os.Remove("test/one/two")
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
}

os.RemoveAll

强制删除目录以及目录汇中的文件

func RemoveAll(path string) error {
	return removeAll(path)
}

func removeAllDir() {
    err := os.RemoveAll("test")
    if err != nil {
        fmt.Printf("err: %v\n", err)
    }
}

os.Getwd

获得工作目录

func Getwd() (dir string, err error) {}
func getWd() {
    dir, err := os.Getwd()
    if err != nil {
        fmt.Printf("err: %v\n", err)
    } else {
        fmt.Printf("dir: %v\n", dir)
    }
}

os.Chdir

修改工作目录

//改变工作目录到f,其中f必须为一个目录,否则便会报错
func (f *File) Chdir() error
func chDir() {
    err := os.Chdir("d:/go/project")
    if err != nil {
        fmt.Printf("err: %v\n", err)
    }
    fmt.Println(os.Getwd())
}

os.TempDir

获得临时目录

func TempDir() string {
	return tempDir()
}
func tempDir() {
    s := os.TempDir()
    fmt.Printf("s: %v\n", s)
}

os.Rename

重命名文件

func Rename(oldpath, newpath string) error {
	return rename(oldpath, newpath)
}
func renameFile() {
    err := os.Rename("test.txt", "test2.txt")
    if err != nil {
        fmt.Printf("err: %v\n", err)
    }
}
func renameDir() {
    err := os.Rename("66", "6666")
    if err != nil {
        fmt.Printf("err: %v\n", err)
    }
}

os.Chmod

修改文件权限

func Chmod(name string, mode FileMode) error { 
    return chmod(name, mode) 
}
func chmod() {
	err := os.Chmod("test2.txt", 0111)
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
}

打包linux测试

SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build main.go

os.Chown

修改文件所有者

func Chown(name string, uid, gid int) error {}

cat /etc/passwd 查看uid和gid

func chown() {
	err := os.Chown("test2.txt", 10, 10)
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
}

文件

打开模式

const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
    O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
    O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
    O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件
    O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用,文件必须不存在
    O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O
    O_TRUNC  int = syscall.O_TRUNC  // 如果可能,打开时清空文件
)

 // 创建一个空文件,注意当文件已经存在时,会直接覆盖掉原文件,不会报错
func Create(name string) (file *File, err error)
// 打开一个文件,注意打开的文件只能读,不能写
func Open(name string) (file *File, err error) 
// 以指定的权限打开文件
func OpenFile(name string, flag int, perm FileMode) (file *File, err error) 
// 关闭文件,关闭后不可读写
func (f *File) Close() error 

其实os.Create 等价于:OpenFile(name, O_RDWF|O_CREATE|O_TRUNK, 0666)

文件读取

// 获取文件的信息,里面有文件的名称,大小,修改时间等
func (f *File) Stat() (fi FileInfo, err error) 
// 从文件中一次性读取b大小的数据,当读到文件结尾时,返回一个EOF错误
func (f *File) Read(b []byte) (n int, err error) 
// 从文件中指定的位置(off)一次性读取b大小的数据
func (f *File) ReadAt(b []byte, off int64) (n int, err error) 
// 读取目录并返回排好序的文件以及子目录名切片
func ReadDir(name string) ([]DirEntry, error) 
//Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。
func (f *File) Seek(offset int64, whence int) (ret int64, err error)

文件写

//Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
func (f *File) Write(b []byte) (n int, err error)
//WriteString类似Write,但接受一个字符串参数。
func (f *File) WriteString(s string) (ret int, err error)
//WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
func (f *File) WriteAt(b []byte, off int64) (n int, err error)

进程相关

// 让当前程序以给出的状态码(code)退出。一般来说,状态码0表示成功,非0表示出错。程序会立刻终止,defer的函数不会被执行。
func Exit(code int) 
// 获取调用者的用户id
func Getuid() int 
// 获取调用者的有效用户id
func Geteuid() int 
 // 获取调用者的组id
func Getgid() int
// 获取调用者的有效组id
func Getegid() int 
// 获取调用者所在的所有组的组id
func Getgroups() ([]int, error) 
// 获取调用者所在进程的进程id
func Getpid() int 
// 获取调用者所在进程的父进程的进程id
func Getppid() int 

Signal

func main() {
	go a()
	go b()
	ch := make(chan os.Signal)
	signal.Notify(ch, os.Kill, os.Interrupt)
	c := <-ch
	log.Println(c)
}

func b() {
	fmt.Println("b")
}

func a() {
	fmt.Println("a")
}

环境相关

// 获取主机名
func Hostname() (name string, err error) 
// 获取某个环境变量
func Getenv(key string) string  
// 设置一个环境变量,失败返回错误,经测试当前设置的环境变量只在 当前进程有效(当前进程衍生的所有的go程都可以拿到,子go程与父go程的环境变量可以互相获取);进程退出消失
func Setenv(key, value string) error 
// 删除当前程序已有的所有环境变量。不会影响当前电脑系统的环境变量,这些环境变量都是对当前go程序而言的
func Clearenv() 

三、time

时间在日常编程中使用非常多。time标准库中日历的计算采用的是公历

Time类型

  • Time代表一个纳秒精度的时间点。

  • 程序中应使用Time类型值来保存和传递时间,而不能用指针。就是说,表示时间的变量和字段,应为time.Time类型,而不是*time.Time.类型。

  • 一个Time类型值可以被多个goroutine同时使用。

  • 时间点可以使用BeforeAfterEqual方法进行比较。

  • Sub方法让两个时间点相减,生成一个Duration类型值(代表时间段)。

  • Add方法给一个时间点加上一个时间段,生成一个新的Time类型时间点。

  • Time零值代表时间点January 1, year 1, 00:00:00.000000000 UTC。因为本时间点一般不会出现在使用中,IsZero方法提供了检验时间是否显式初始化的一个简单途径。

  • 每一个时间都具有一个地点信息(及对应地点的时区信息),当计算时间的表示格式时,如FormatHourYear等方法,都会考虑该信息。

  • LocalUTCIn方法返回一个指定时区(但指向同一时间点)的Time。修改地点/时区信息只是会改变其表示;不会修改被表示的时间点,因此也不会影响其计算。

func timeDemo() {
	now := time.Now() //获取当前时间
	fmt.Printf("current time:%v\n", now)

	year := now.Year()     //年
	month := now.Month()   //月
	day := now.Day()       //日
	hour := now.Hour()     //小时
	minute := now.Minute() //分钟
	second := now.Second() //秒
	//02d输出的整数不足两位 用0补足
	fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}

时间戳

时间戳是自1970年1月1日0时0分0秒至当前时间的总毫秒数。它也被称为Unix时间戳(UnixTimestamp)。

这里指的是UTC时间,比北京时间晚8个小时。

func timestampDemo() {
    now := time.Now()            //获取当前时间
    timestamp1 := now.Unix()     //时间戳
    timestamp2 := now.UnixNano() //纳秒时间戳
    fmt.Printf("current timestamp1:%v\n", timestamp1)
    fmt.Printf("current timestamp2:%v\n", timestamp2)
}

Parse解析时间

func Parse(layout, value string) (Time, error)

解析一个格式化的时间字符串并返回它代表的时间,如果缺少表示时区的信息,Parse会将时区设置为UTC。

func ParseInLocation(layout, value string, loc *Location) (Time, error)

ParseInLocation类似Parse但有两个重要的不同之处。第一,当缺少时区信息时,Parse将时间解释为UTC时间,而ParseInLocation将返回值的Location设置为loc;第二,当时间字符串提供了时区偏移量信息时,Parse会尝试去匹配本地时区,而ParseInLocation会去匹配loc。

layout的时间必须是"2006-01-02 15:04:05"这个时间,当然格式不一定是这个,时间一定得是,这是go诞生的时间

func timeParse() {
	t, err := time.Parse("2006-01-02 15:04:05", "2022-07-28 18:06:00")
	if err != nil {
		panic(err)
	}
	fmt.Println(t)
	now := time.Now()
	fmt.Println(now)
	// 加载时区
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		fmt.Println(err)
		return
	}
	// 按照指定时区和指定格式解析字符串时间
	timeObj, err := time.ParseInLocation("2006/01/02 15:04:05", now.Format("2006/01/02 15:04:05"), loc)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(timeObj)

}

格式化时间

func (t Time) Format(layout string) string

Format根据layout指定的格式返回t代表的时间点的格式化文本表示。

time.Unix()

func Unix(sec int64, nsec int64) Time

Unix创建一个本地时间,对应sec和nsec表示的Unix时间(从January 1, 1970 UTC至该时间的秒数和纳秒数)。

nsec的值在[0, 999999999]范围内是合法的。

时间间隔

time.Duration是time包定义的一个类型,它代表两个时间点之间经过的时间,以纳秒为单位。time.Duration表示一段时间间隔,可表示的最长时间段大约290年。

time包中定义的时间间隔类型的常量如下:

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)

例如:time.Duration表示1纳秒,time.Second表示1秒。

时间计算

Add

func (t Time) Add(d Duration) Time

Add返回时间点t+d。

Sub

求两个时间之间的差值

    func (t Time) Sub(u Time) Duration

返回一个时间段t-u。如果结果超出了Duration可以表示的最大值/最小值,将返回最大值/最小值。

要获取时间点t-d(d为Duration),可以使用t.Add(-d)。

Equal

    func (t Time) Equal(u Time) bool

判断两个时间是否相同,会考虑时区的影响,因此不同时区标准的时间也可以正确比较。

本方法和用t==u不同,这种方法还会比较地点和时区信息。

Before

    func (t Time) Before(u Time) bool

如果t代表的时间点在u之前,返回真;否则返回假。

After

    func (t Time) After(u Time) bool

如果t代表的时间点在u之后,返回真;否则返回假。

定时器

使用time.Tick(时间间隔)来设置定时器,定时器的本质上是一个通道(channel)

func tickDemo() {
    ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器
    for i := range ticker {
        fmt.Println(i)//每秒都会执行的任务
    }
}
time.AfterFunc(time.Second*10, func() {
		 fmt.Println("10秒后执行")
})
package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
/**
*ticker只要定义完成,从此刻开始计时,不需要任何其他的操作,每隔固定时间都会触发。
*timer定时器,是到固定时间后会执行一次
*如果timer定时器要每隔间隔的时间执行,实现ticker的效果,使用 func (t *Timer) Reset(d Duration) bool
 */
func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    //NewTimer 创建一个 Timer,它会在最少过去时间段 d 后到期,向其自身的 C 字段发送当时的时间
    timer1 := time.NewTimer(2 * time.Second)
 
    //NewTicker 返回一个新的 Ticker,该 Ticker 包含一个通道字段,并会每隔时间段 d 就向该通道发送当时的时间。它会调  
   //整时间间隔或者丢弃 tick 信息以适应反应慢的接收者。如果d <= 0会触发panic。关闭该 Ticker 可            
   //以释放相关资源。
    ticker1 := time.NewTicker(2 * time.Second)
 
    go func(t *time.Ticker) {
        defer wg.Done()
        for {
            <-t.C
            fmt.Println("get ticker1", time.Now().Format("2006-01-02 15:04:05"))
        }
    }(ticker1)
 
    go func(t *time.Timer) {
        defer wg.Done()
        for {
            <-t.C
            fmt.Println("get timer", time.Now().Format("2006-01-02 15:04:05"))
            //Reset 使 t 重新开始计时,(本方法返回后再)等待时间段 d 过去后到期。如果调用时t     
            //还在等待中会返回真;如果 t已经到期或者被停止了会返回假。
            t.Reset(2 * time.Second)
        }
    }(timer1)
 
    wg.Wait()
}

四、log

golang内置了log包,实现简单的日志服务。通过调用log包的函数,可以实现简单的日志打印功能。

log包定义了Logger类型,该类型提供了一些格式化输出的方法。

log包也提供了一个预定义的“标准”logger,可以通过调用函数Print系列(Print|Printf|Println)、Fatal系列(Fatal|Fatalf|Fatalln)、和Panic系列(Panic|Panicf|Panicln)来使用。

og包中有3个系列的日志打印函数,分别print系列panic系列fatal系列.

函数系列说明作用
PrintPrint/Printf/Println单纯打印日志
PanicPanic/Panicf/Panicln打印日志,抛出panic异常
FatalFatal/Fatalf/Fatalln打印日志,强制结束程序(os.Exit(1)),defer函数不会执行

log包主要提供了3类接口,分别是print系列、panic系列、fatal系列,对每一类接口其提供了3种调用方式

Print

单纯打印日志

Panic

打印出日志并且抛出panic异常,在panic之后声明的代码将不会执行。

Fatal

将日志内容打印输出,接着调用系统的os.Exit(1)接口,强制退出程序并返回状态1,但是有一点需要注意的是,由于直接调用系统os接口退出,defer函数不会调用。

日志配置

默认情况下log只会打印出时间,但是实际情况下我们还需要获取文件名,行号等信息,log包提供给我们定制的接口。

方法说明
func Flags() int返回标准log输出配置
func SetFlags(flag int)设置标准log输出配置
const (
    // 控制输出日志信息的细节,不能控制输出的顺序和格式。
    // 输出的日志在每一项后会有一个冒号分隔,例如2022/07/23 01:23:23.123123 /a/b/c/d.go:23: message
    Ldate         = 1 << iota     // 日期,2022/07/23
    Ltime                         // 时间,01:23:23
    Lmicroseconds                 // 微秒级别的时间,01:23:23.123123(用于增强Ltime位)
    Llongfile                     // 文件全路径名+行号,/a/b/c/d.go:23
    Lshortfile                    // 文件名+行号,d.go:23(会覆盖掉Llongfile)
    LUTC                          // 使用UTC时间
    LstdFlags     = Ldate | Ltime // 标准logger的初始值
)
package main

import (
	"fmt"
	"log"
)

func main() {
	i := log.Flags()
	fmt.Printf("i: %v\n", i)
	log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
	log.Print("this is a log")
}

前缀配置

方法说明
func Prefix() string返回日志的前缀配置
func SetPrefix(prefix string)设置日志前缀

输出到文件

log包提供了func SetOutput(w io.Writer)函数,将日志输出到文件中。

自定义Logger

log包中提供了func New(out io.Writer, prefix string, flag int) *Logger函数来实现自定义logger。

package main

import (
	"log"
	"os"
)

var logger *log.Logger

func init() {
	logFile, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Panic("打开日志文件异常")
	}
	logger = log.New(logFile, "[Mylog]", log.Ldate|log.Ltime|log.Lshortfile)
}

func main() {
	logger.Println("自定义logger")
}

五、error

errors包实现了操作错误的函数。go语言使用error类型来返回函数执行过程中遇到的错误,如果返回的error值为nil,则表示未遇到错误,否则error会返回一个字符串,用于说明遇到了什么错误。

type error interface {
    Error() string
}

error不一定表示一个错误,它可以表示任何信息,比如io包中就用error类型的io.EOF表示数据读取结束,而不是遇到了什么错误。

func New(text string) error

自定义错误

go允许函数具有多返回值,但通常你不会想写太多的返回值在函数定义上,而标准库内置的error String类型由于只能表达字符串错误信息显然受限。

所以,可以通过实现error接口的方式,来扩展错误返回。

package main

import (
	"fmt"
	"time"
)

// 自定义error类型
type MyError struct {
	When time.Time //发生错误的时间
	What string    //错误文本信息
}

func (e MyError) Error() string {
	return fmt.Sprintf("%v: %v", e.When, e.What)
}

func oops() error {
	return MyError{
		time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),
		"the file system has gone away",
	}
}

func main() {
	if err := oops(); err != nil {
		fmt.Println(err)
	}
}

六、bytes

bytes包提供了对字节切片进行读写操作的一系列函数,字节切片处理的函数比较多分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。

常用函数

转换

函数说明
func ToUpper(s []byte) []byte将 s 中的所有字符修改为大写格式返回。
func ToLower(s []byte) []byte将 s 中的所有字符修改为小写格式返回
func ToTitle(s []byte) []byte将 s 中的所有字符修改为标题格式返回
func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte使用指定的映射表将 s 中的所有字符修改为大写格式返回
func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte使用指定的映射表将 s 中的所有字符修改为小写格式返回
func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte使用指定的映射表将 s 中的所有字符修改为标题格式返回
func Title(s []byte) []byte将 s 中的所有单词的首字符修改为 Title 格式返回。(缺点:不能很好的处理以 Unicode 标点符号分隔的单词。)

比较

函数说明
func Compare(a, b []byte) int比较两个 []byte,nil 参数相当于空 []byte。a < b 返回 -1;a == b 返回 0;a > b 返回 1
func Equal(a, b []byte) bool判断 a、b 是否相等,nil 参数相当于空 []byte
func EqualFold(s, t []byte) bool判断 s、t 是否相似,忽略大写、小写、标题三种格式的区别

清理

  • func Trim(s []byte, cutset string) []byte

    去掉 s 两边包含在 cutset 中的字符(返回 s 的切片

  • func TrimLeft(s []byte, cutset string) []byte

    去掉 s 左边包含在 cutset 中的字符(返回 s 的切片)

  • func TrimRight(s []byte, cutset string) []byte

    去掉 s 右边包含在 cutset 中的字符(返回 s 的切片)

  • func TrimFunc(s []byte, f func(r rune) bool) []byte

    去掉 s 两边符合 f函数====返回值是true还是false 要求的字符(返回 s 的切片)

  • func TrimLeftFunc(s []byte, f func(r rune) bool) []byte

    去掉 s左边符合 f函数====返回值是true还是false 要求的字符(返回 s 的切片)

  • func TrimRightFunc(s []byte, f func(r rune) bool) []byte

    去掉 s右边符合 f函数====返回值是true还是false 要求的字符(返回 s 的切片)

  • func TrimSpace(s []byte) []byte

    去掉 s 两边的空白(unicode.IsSpace)(返回 s 的切片)

  • func TrimPrefix(s, prefix []byte) []byte

    去掉 s 的前缀 prefix(返回 s 的切片)

  • func TrimSuffix(s, suffix []byte) []byte

    去掉 s 的后缀 suffix(返回 s 的切片)

拆合

  • func Split(s, sep []byte) [][]byte

    Split 以 sep 为分隔符将 s 切分成多个子串,结果不包含分隔符。如果 sep 为空,则将 s 切分成 Unicode 字符列表。

  • func SplitN(s, sep []byte, n int) [][]byte

    SplitN 可以指定切分次数 n,超出 n 的部分将不进行切分。

  • func SplitAfter(s, sep []byte) [][]byte

    功能同 Split,只不过结果包含分隔符(在各个子串尾部)。

  • func SplitAfterN(s, sep []byte, n int) [][]byte

    功能同 SplitN,只不过结果包含分隔符(在各个子串尾部)。

  • func Fields(s []byte) [][]byte

    以连续空白为分隔符将 s 切分成多个子串,结果不包含分隔符。

  • func FieldsFunc(s []byte, f func(rune) bool) [][]byte

    以符合 f 的字符为分隔符将 s 切分成多个子串,结果不包含分隔符。

  • func Join(s [][]byte, sep []byte) []byte

    以 sep 为连接符,将子串列表 s 连接成一个字节串。

  • func Repeat(b []byte, count int) []byte

    将子串 b 重复 count 次后返回。

字串

  • func HasPrefix(s, prefix []byte) bool

    判断 s 是否有前缀 prefix

  • func HasSuffix(s, suffix []byte) bool

    判断 s 是否有后缀 suffix

  • func Contains(b, subslice []byte) bool

    判断 b 中是否包含子串 subslice

  • func ContainsRune(b []byte, r rune) bool

    判断 b 中是否包含子串 字符 r

  • func ContainsAny(b []byte, chars string) bool

    判断 b 中是否包含 chars 中的任何一个字符

  • func Index(s, sep []byte) int

    查找子串 sep在 s 中第一次出现的位置,找不到则返回 -1

  • func IndexByte(s []byte, c byte) int

    查找子串 字节 c在 s 中第一次出现的位置,找不到则返回 -1

  • func IndexRune(s []byte, r rune) int

    查找子串字符 r在 s 中第一次出现的位置,找不到则返回 -1

  • func IndexAny(s []byte, chars string) int

    查找 chars 中的任何一个字符在 s 中第一次出现的位置,找不到则返回 -1。

  • func IndexFunc(s []byte, f func(r rune) bool) int

    查找符合 f 的字符在 s 中第一次出现的位置,找不到则返回 -1。

  • func LastIndex(s, sep []byte) int

    功能同上,只不过查找最后一次出现的位置。

  • func LastIndexByte(s []byte, c byte) int

    功能同上,只不过查找最后一次出现的位置。

  • func LastIndexAny(s []byte, chars string) int

    功能同上,只不过查找最后一次出现的位置。

  • func LastIndexFunc(s []byte, f func(r rune) bool) int

    功能同上,只不过查找最后一次出现的位置。

  • func Count(s, sep []byte) int

    获取 sep 在 s 中出现的次数(sep 不能重叠)。

替换

  • func Replace(s, old, new []byte, n int) []byte

    将 s 中前 n 个 old 替换为 new,n < 0 则替换全部。

  • func Map(mapping func(r rune) rune, s []byte) []byte

    将 s 中的字符替换为 mapping® 的返回值,如果 mapping 返回负值,则丢弃该字符。

  • func Runes(s []byte) []rune

    将 s 转换为 []rune 类型返回

Buffer类型

缓冲区是具有读取和写入方法的可变大小的字节缓冲区

Buffer的零值是准备使用的空缓冲区

type Buffer struct {
	buf      []byte // contents are the bytes buf[off : len(buf)]
	off      int    // read at &buf[off], write at &buf[len(buf)]
	lastRead readOp // last read operation, so that Unread* can work correctly.
}

声明buffer

  • var b bytes.Buffer

    直接定义一个Buffer变量,不用初始化,可以直接使用

  • b := new(bytes.Buffer)

    使用New返回Buffer变量

  • b := bytes.NewBuffer(s []byte)

    从一个[]byte切片,构造一个Buffer

  • b := bytes.NewBufferString(s string)

    从一个string变量,构造一个Buffer

往Buffer中写入数据

  • b.Write(d []byte)

    将切片d写入Buffer数据

  • b.WriteString(s string)

    将字符串s写入Buffer尾部

  • b.WriteByte(c byte)

    将字符c写入Buffer尾部

  • b.WriteRune(r rune)

    将一个rune类型的数据放到缓冲器的尾部

  • b.WriteTo(w io.Writer)

    将Buffer中的内容输出到实现了io.Writer接口的可写入对象中

从Buffer中读取数据

  • b.Read(c)

    一次读取8个byte到c容器中,每次读取新的8个byte覆盖c中原来的内容

  • b.ReadByte()

    读取第一个byte,b的第一个byte被拿掉,赋值给 a => a, _ := b.ReadByte()

  • b.ReadRune()

    读取第一个rune,b的第一个rune被拿掉,赋值给 r => r, _ := b.ReadRune()

  • b.ReadBytes(delimiter byte)

    需要一个byte作为分隔符,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回,作为byte类型的slice,返回后,缓冲器也会空掉一部分

  • b.ReadString(delimiter byte)

    需要一个byte作为分隔符,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回,作为字符串返回,返回后,缓冲器也会空掉一部分

  • b.ReadFrom(i io.Reader)

    从一个实现io.Reader接口的r,把r里的内容读到缓冲器里,n返回读的数量

其他方法

  • func (b *Buffer) Len() int

    未读取部分的数据长度

  • func (b *Buffer) Cap() int

    获取缓存的容量

  • func (b *Buffer) Next(n int) []byte

    读取前 n 字节的数据并以切片形式返回,如果数据长度小于 n,则全部读取。切片只在下一次读写操作前合法。

  • func (b *Buffer) Bytes() []byte

    引用未读取部分的数据切片(不移动读取位置)

  • func (b *Buffer) String() string

    返回未读取部分的数据字符串(不移动读取位置)

  • func (b *Buffer) Grow(n int)

    自动增加缓存容量,以保证有 n 字节的剩余空间。如果 n 小于 0 或无法增加容量则会 panic。

  • func (b *Buffer) Truncate(n int)

    将数据长度截短到 n 字节,如果 n 小于 0 或大于 Cap 则 panic。

  • func (b *Buffer) Reset()

    重设缓冲区,清空所有数据(包括初始内容)。

Reader类型

type Reader struct {
	s        []byte
	i        int64 // current reading index
	prevRune int   // index of previous rune; or < 0
}

Reader实现了io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, io.ByteScanner, io.RuneScanner接口

  • func NewReader(b []byte) *Reader

    将 b 包装成 bytes.Reader 对象。

  • func (r *Reader) Len() int

    返回未读取部分的数据长度

  • func (r *Reader) Size() int64

    返回底层数据的总长度,方便 ReadAt 使用,返回值永远不变。

  • func (r *Reader) Reset(b []byte)

    将底层数据切换为 b,同时复位所有标记(读取位置等信息)。

七、io

io包中提供I/O原始操作的一系列接口。它主要包装了一些已有的实现,如 os 包中的那些,并将这些抽象成为实用性的功能和一些其他相关的接口。

错误变量

  • var EOF = errors.New(“EOF”)
    正常输入结束Read返回EOF,如果在一个结构化数据流中EOF在不期望的位置出现了,则应返回错误ErrUnexpectedEOF或者其它给出更多细节的错误。

  • var ErrClosedPipe = errors.New(“io: read/write on closed pipe”)
    当从一个已关闭的Pipe读取或者写入时,会返回ErrClosedPipe。

  • var ErrNoProgress = errors.New(“multiple Read calls return no data or error”)
    某些使用io.Reader接口的客户端如果多次调用Read都不返回数据也不返回错误时,就会返回本错误,一般来说是io.Reader的实现有问题的标志。

  • var ErrShortBuffer = errors.New(“short buffer”)
    ErrShortBuffer表示读取操作需要大缓冲,但提供的缓冲不够大。

  • var ErrShortWrite = errors.New(“short write”)
    ErrShortWrite表示写入操作写入的数据比提供的少,却没有显式的返回错误。

  • var ErrUnexpectedEOF = errors.New(“unexpected EOF”)
    ErrUnexpectedEOF表示在读取一个固定尺寸的块或者数据结构时,在读取未完全时遇到了EOF。

基础接口

Reader接口

type Reader interface {
	Read(p []byte) (n int, err error)	
}

Read 将 len个字节读取到 p 中。它返回读取的字节数 n(0 <= n <= len)以及任何遇到的错误。即使 Read 返回的 n < len,它也会在调用过程中使用 p的全部作为暂存空间。若一些数据可用但不到 len 个字节,Read 会照例返回可用的东西,而不是等待更多。

当 Read 在成功读取 n > 0 个字节后遇到一个错误或 EOF 情况,它就会返回读取的字节数。它会从相同的调用中返回(非nil的)错误或从随后的调用中返回错误(和 n == 0)。这种一般情况的一个例子就是 Reader 在输入流结束时会返回一个非零的字节数,可能的返回不是 err == EOF 就是 err == nil。无论如何,下一个 Read 都应当返回 0, EOF。

调用者应当总在考虑到错误 err 前处理 n > 0 的字节。这样做可以在读取一些字节,以及允许的 EOF 行为后正确地处理I/O错误。

Read 的实现会阻止返回零字节的计数和一个 nil 错误,调用者应将这种情况视作空操作。

Writer接口

type Writerinterface {
	Write(p []byte) (n int, err error)	
}

Write 将 len个字节从 p 中写入到基本数据流中。它返回从 p 中被写入的字节数n(0 <= n <= len)以及任何遇到的引起写入提前停止的错误。若 Write 返回的n < len,它就必须返回一个非nil的错误。Write 不能修改此切片的数据,即便它是临时的。

Seeker接口

type Seeker interface {
    Seek(offset int64, whence int) (int64, error)
}

Seeker 用来移动数据的读写指针

Seek 设置下一次读写操作的指针位置,每次的读写操作都是从指针位置开始的

  • whence 的含义:

    • 如果 whence 为 0:表示从数据的开头开始移动指针
    • 如果 whence 为 1:表示从数据的当前指针位置开始移动指针
    • 如果 whence 为 2:表示从数据的尾部开始移动指针
  • offset 是指针移动的偏移量

    返回移动后的指针位置和移动过程中遇到的任何错误

Closer接口

type Closer interface {
	Close() error
}

Closer关闭的接口, 带有Close() 方法, 但是行为没有定义,所以 可以特定行为来实现
在整个标准库内都没有对Closer的引用,只有实现,用法都是开启某某连接/流,在用完/报错后在进行Close的操作。

组合接口

组合接口是对多个接口进行了组合,当同时实现多个接口时,可以使用组合接口进行传递

ReadWriter接口

type ReadWriter interface {
	Reader
	Writer
}

ReadWriter接口聚合了基本的读写操作。

ReadCloser接口

type ReadCloser interface {
	Reader
	Closer
}

ReadCloser就是Reader+Closer,例如在ioutil中的NopCloser方法返回的就是一个ReadCloser,但是里面的Close就是个空函数,毫无作用。

WriteCloser接口

type WriteCloser interface {
	Writer
	Closer
}

WriteCloser接口聚合了基本的写入和关闭操作。

ReadWriteCloser接口

type ReadWriteCloser interface {
	Reader
	Writer
	Closer
}

ReadWriteCloser接口聚合了基本的读写和关闭操作。

ReadSeeker接口

type ReadSeeker interface {
	Reader
	Seeker
}

ReadSeeker接口聚合了基本的读取和移位操作。

WriteSeeker接口

type WriteSeeker interface {
	Writer
	Seeker
}

WriteSeeker接口聚合了基本的写入和移位操作。

ReadWriteSeeker接口

type ReadWriteSeeker interface {
	Reader
	Writer
	Seeker
}

ReadWriteSeeker接口聚合了基本的读写和移位操作

指定读写器读写接口

ReaderFrom接口

type ReaderFrom interface {
	ReadFrom(r Reader) (n int64, err error)		
}

ReadFrom 从 r 中读取数据到对象的数据流中
直到 r 返回 EOF 或 r 出现读取错误为止
返回值 n 是读取的字节数
返回值 err 就是 r 的返回值 err

WriterTo接口

type WriterTo interface {
	WriteTo(w Writer) (n int64, err error)		
}

WriterTo 将对象的数据流写入到 w 中
直到对象的数据流全部写入完毕或遇到写入错误为止
返回值 n 是写入的字节数
返回值 err 就是 w 的返回值 err

指定偏移量读写接口

ReaderAt接口

type ReaderAt interface {
    ReadAt(p []byte, off int64) (n int, err error)
}

ReadAt 从对象数据流的 off 处读出数据到 p 中

  • 忽略数据的读写指针,从数据的起始位置偏移 off 处开始读取
  • 如果对象的数据流只有部分可用,不足以填满 p则 ReadAt 将等待所有数据可用之后,继续向 p 中写入直到将 p 填满后再返回,在这点上 ReadAt 要比 Read 更严格
  • 返回读取的字节数 n 和读取时遇到的错误
  • 如果 n < len,则需要返回一个 err 值来说明为什么没有将 p 填满(比如 EOF)
  • 如果 n > len,而且对象的数据没有全部读完,则err 将返回 nil
  • 如果 n = len,而且对象的数据刚好全部读完,则err 将返回 EOF 或者 nil(不确定)

WriterAt接口

type WriterAt interface {
    WriteAt(p []byte, off int64) (n int, err error)
}

WriteAt 将 p 中的数据写入到对象数据流的 off 处

  • 忽略数据的读写指针,从数据的起始位置偏移 off 处开始写入
  • 返回写入的字节数和写入时遇到的错误
  • 如果 n < len,则必须返回一个 err 值来说明为什么没有将 p 完全写入

单个字节读写接口

ByteReader接口

type ByteReader interface {
	ReadByte() (byte, error)
}

ByteReader是基本的ReadByte方法的包装。
ReadByte读取输入中的单个字节并返回。如果没有字节可读取,会返回错误。

ByteScanner接口

type ByteScanner interface {
    ByteReader
    UnreadByte() error
}

ByteScanner接口在基本的ReadByte方法之外还添加了UnreadByte方法。

UnreadByte方法让下一次调用ReadByte时返回之前调用ReadByte时返回的同一个字节。连续调用两次UnreadByte方法而中间没有调用ReadByte时,可能会导致错误。

ByteWriter接口

type ByteWriter interface {
	WriteByte(c byte) error
}

包装 WriteByte 单个字节写入方法的接口

RuneReader接口

type RuneReader interface {
	ReadRune() (r rune, size int, err error)	
}

ReadRune 方法的包装,读取单个UTF-8编码的Unicode字符,并返回rune及其字节大小。如果没有可用字符,将设置err

RuneScanner接口

type RuneScanner interface {
	RuneReader
	UnreadRune() error
}

RuneScanner接口在基本的ReadRune方法之外还添加了UnreadRune方法。

UnreadRune方法让下一次调用ReadRune时返回之前调用ReadRune时返回的同一个utf-8字符。连续调用两次UnreadRune方法而中间没有调用ReadRune时,可能会导致错误。

StringWriter接口

type StringWriter interface {
	WriteString(s string) (n int, err error)
}

字符串写入方法WriteString的包装

结构体

LimitedReader

type LimitedReader struct {
    R   Reader // underlying reader
    N   int64  // max bytes remaining
}

LimitedReader从R读取,但将返回的数据量限制为N个字节。每次读取更新N以标记剩余可以读取的字节数。Read在N<=0时或基础R返回EOF时返回EOF。

具体实现方法为:func LimitReader(r Reader, n int64) Reader

PipeReader

type PipeReader struct {
    // 内含隐藏或非导出字段
}

PipeReader是一个管道的读取端。

具体实现方法有:

  1. func (r *PipeReader) Read(data []byte) (n int, err error)
    Read实现了标准的读取接口:它从管道中读取数据,阻塞直到写入端到达或写入端被关闭。如果用错误关闭写入端,则返回错误为ERR;否则ERR为EOF。
  2. func (r *PipeReader) Close() error
    Close关闭读取器;关闭后如果对管道的写入端进行写入操作,就会返回(0, ErrClosedPip)。
  3. func (r *PipeReader) CloseWithError(err error) error
    CloseWithError类似Close方法,但将调用Write时返回的错误改为err。

PipeWriter

type PipeWriter struct {
    // 内含隐藏或非导出字段
}

PipeWriter是一个管道的写入端。
具体实现方法有:

  1. func (w *PipeWriter) Write(data []byte) (n int, err error)
    Write实现了标准的写接口:它将数据写入管道,直到一个或多个读取端消耗完所有数据或读取端关闭为止。如果以错误关闭读取端,则该错误将作为ERR返回;否则ERR将为ErrClosedPipe。
  2. func (w *PipeWriter) Close() error
    Close关闭写入器;关闭后如果对管道的读取端进行读取操作,就会返回(0, EOF)。
  3. func (w *PipeWriter) CloseWithError(err error) error
    CloseWithError类似Close方法,但将调用Read时返回的错误改为err。

注:以上两个结构体PipeWriter与PipeReader是结合使用的需要用Pipe()方法进行创建。

SectionReader

type SectionReader struct {
    // contains filtered or unexported fields
}

SectionReader在ReaderAt的基础上实现了Read,Seek和ReadAt。
具体实现方法有:

  1. func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader
    结构体SectionReader的创建方法
    NewSectionReader返回一个SectionReader,它从r开始读取,偏移量为off,并在n个字节后以EOF停止。
  2. func (s *SectionReader) Read(p []byte) (n int, err error)
    实现了接口Reader的Read方法
  3. func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
    实现了接口ReaderAt的ReadAt方法
  4. func (s *SectionReader) Seek(offset int64, whence int) (int64, error)
    实现了接口Seeker的Seek方法
    func (*SectionReader) Size
  5. func (s *SectionReader) Size() int64
    Size返回以字节为单位的片段大小。

供外部调用的函数

Copy

func Copy(dst Writer, src Reader) (written int64, err error)

将副本从src复制到dst,直到在src上达到EOF或发生错误。它返回复制的字节数和复制时遇到的第一个错误(如果有)。 成功的复制将返回err == nil而不是err == EOF。因为复制被定义为从src读取直到EOF,所以它不会将读取的EOF视为要报告的错误。 如果src实现WriterTo接口,则通过调用src.WriteTo(dst)实现该副本。否则,如果dst实现了ReaderFrom接口,则通过调用dst.ReadFrom(src)实现该副本。

CopyBuffer

func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)

CopyBuffer与Copy相同,区别在于CopyBuffer逐步遍历提供的缓冲区(如果需要),而不是分配临时缓冲区。如果buf为nil,则分配一个;如果长度为零,则CopyBuffer会panic报错。 如果src实现WriterTo或dst实现ReaderFrom,则buf将不用于执行复制。

CopyN

func CopyN(dst Writer, src Reader, n int64) (written int64, err error)

CopyN将n个字节(或直到出错)从src复制到dst。它返回复制的字节数以及复制时遇到的最早错误。返回时,只有err == nil时,writte == n。 如果dst实现了ReaderFrom接口,则使用该接口实现副本。

LimitReader

func LimitReader(r Reader, n int64) Reader

LimitedReader从r读取,但将返回的数据量限制为n个字节。每次读取更新n以标记剩余可以读取的字节数。Read在n<=0时或基础r返回EOF时返回EOF。

MultiReader

func MultiReader(readers ...Reader) Reader

MultiReader返回一个Reader,它是所提供的输入阅读器的逻辑串联。它们被顺序读取。一旦所有输入均返回EOF,读取将返回EOF。如果任何读取器返回非零,非EOF错误,则Read将返回该错误。

MultiWriter

func MultiWriter(writers ...Writer) Writer

MultiWriter创建一个Writers,将其写入复制到所有提供的写入器中,类似于Unix tee(1)命令。 每个写入一次写入每个列出的写入器。如果列出的写程序返回错误,则整个写操作将停止并返回错误;它不会在列表中继续下去。

Pipe

func Pipe() (*PipeReader, *PipeWriter)

Pipe创建一个同步的内存管道。
可用于连接期望io.Reader的代码和期望io.Writer的代码。

管道上的读和写是一对一匹配的,除非需要多次读取才能使用单次写入。也就是说,每次对PipeWriter的写入都将阻塞,直到它满足从PipeReader读取的一个或多个读取,这些读取会完全消耗已写入的数据。

数据直接从Write复制到相应的Read (或Reads);没有内部缓冲。
对读的并行调用和对写的并行调用也是安全的:单个调用将按顺序执行。

ReadAll

func ReadAll(r Reader) ([]byte, error)

ReadAll从r读取,直到出现错误或EOF,并返回其读取的数据。成功的调用返回errnil,而不是errEOF。由于ReadAll定义为从src读取直到EOF,因此它不会将读取的EOF视为要报告的错误。

ReadAtLeast

func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

ReadAtLeast从r读取到buf,直到它至少读取了min字节。它返回复制的字节数n,如果读取的字节数少则返回错误。仅当未读取任何字节时,错误才是EOF。如果在读取少于最小字节后发生EOF,则ReadAtLeast返回ErrUnexpectedEOF。如果min大于buf的长度,则ReadAtLeast返回ErrShortBuffer。返回时,当且仅当err == nil时,n> = min。

ReadFull

func ReadFull(r Reader, buf []byte) (n int, err error)

ReadFull将r中的len(buf)个字节准确地读取到buf中。它返回复制的字节数,如果读取的字节数少则返回错误。仅当未读取任何字节时,错误才是EOF。如果在读取了一些但不是全部字节后发生EOF,则ReadFull返回ErrUnexpectedEOF。返回时,当且仅当err == nil时,n == len(buf)。

SectionReader

SectionReader在ReaderAt的基础上实现了Read,Seek和ReadAt。

具体实现方法有:

  1. func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader
    结构体SectionReader的创建方法
    NewSectionReader返回一个SectionReader,它从r开始读取,偏移量为off,并在n个字节后以EOF停止。
  2. func (s *SectionReader) Read(p []byte) (n int, err error)
    实现了接口Reader的Read方法
  3. func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
    实现了接口ReaderAt的ReadAt方法
  4. func (s *SectionReader) Seek(offset int64, whence int) (int64, error)
    实现了接口Seeker的Seek方法
  5. func (s *SectionReader) Size() int64
    Size返回以字节为单位的片段大小。
NewSectionReader
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader

NewSectionReader返回一个SectionReader,它从r开始读取偏移量off,并在n个字节后以EOF停止。

SectionReader.Read
func (s *SectionReader) Read(p []byte) (n int, err error)

实现了接口Reader的Read方法

SectionReader.ReadAt
func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)

实现了接口ReaderAt的ReadAt方法

SectionReader.Seek
func (s *SectionReader) Seek(offset int64, whence int) (int64, error)

实现了接口Seeker的Seek方法

可以看的出来SectionReader是根据ReaderAt实现的,而非Seeker,虽然两者的效果很像,但是ReaderAt读取内容是无视Seeker偏移量的。且在读取数据大小上ReadAt是要比Read严格的,同样的Bytes在Read上即使设大了也会没事,但在ReadAt会报错。

SectionReader.Size
func (s *SectionReader) Size() int64

Size返回以字节为单位的片段大小。

TeeReader

func TeeReader(r Reader, w Writer) Reader

TeeReader返回一个Reader,该Reader向w写入从r读取的内容。通过r执行的所有r读取均与对w的相应写入匹配。没有内部缓冲-写入必须在读取完成之前完成。写入时遇到的任何错误均报告为读取错误。

WriteString

func WriteString(w Writer, s string) (n int, err error)

WriteString将字符串s的内容写入w,w接受字节片。如果w实现StringWriter,则直接调用其WriteString方法。否则,w.Write只调用一次。


http://www.kler.cn/a/569213.html

相关文章:

  • 算法系列之双指针(待完善题目)
  • openssl下aes128算法xts模式加解密运算实例
  • MySQL零基础教程13—分组查询(group by 和 having)
  • 消息中间件应用的常见问题与方案?
  • 华为 Open Gauss 数据库在 Spring Boot 中使用 Flyway
  • 【Delphi】如何解决使用webView2时主界面置顶,而导致网页选择文件对话框被覆盖问题
  • Python的那些事第三十四篇:基于 Plotly 的交互式图表与仪表板设计与应用
  • 【北京迅为】itop-3568 开发板openharmony鸿蒙烧写及测试-第1章 体验OpenHarmony—烧写镜像
  • 6-2JVM解释器
  • docker利用docker-compose-gpu.yml启动RAGFLOW,文档解析出错【亲测已解决】
  • 高效API开发:FastAPI中的缓存技术与性能优化
  • 前缀和算法 算法4
  • unsloth报错FileNotFoundError: [WinError 3] 系统找不到指定的路径。
  • Transformer 代码剖析2 - 模型训练 (pytorch实现)
  • 【大模型学习笔记】0基础本地部署dify教程
  • AI辅助学习vue第十四章
  • 欧拉22.03系统安装离线redis 6.2.5
  • vue3配置端口,比底部vue调试
  • logback日志输出配置范例
  • FPGA AXI-Stream协议详解与仿真实践