Golang标准库os模块-文件目录相关 os标准库实现了平台(操作系统)无关的编程接口。
https://pkg.go.dev/std
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 package mainimport ( "fmt" "os" ) func createFile () { f, err := os.Create("test.txt" ) if err != nil { fmt.Printf("err: %v\n" , err) } else { fmt.Printf("f: %v\n" , f) } } func createDir () { err := os.MkdirAll("test/a/b" , os.ModePerm) if err != nil { fmt.Printf("err: %v\n" , err) } } func removeDir () { err := os.RemoveAll("test" ) if err != nil { fmt.Printf("err: %v\n" , err) } } func getWd () { dir, err := os.Getwd() if err != nil { fmt.Printf("err: %v\n" , err) } else { fmt.Printf("dir: %v\n" , dir) } } func chWd () { err := os.Chdir("d:/" ) if err != nil { fmt.Printf("err: %v\n" , err) } fmt.Println(os.Getwd()) } func getTemp () { s := os.TempDir() fmt.Printf("s: %v\n" , s) } func renameFile () { err := os.Rename("test.txt" , "test2.txt" ) if err != nil { fmt.Printf("err: %v\n" , err) } } func readFile () { b, err := os.ReadFile("test2.txt" ) if err != nil { fmt.Printf("err: %v\n" , err) } else { fmt.Printf("b: %v\n" , string (b[:])) } } func writeFile () { s := "hello world" os.WriteFile("test2.txt" , []byte (s), os.ModePerm) } func main () { }
Golang标准库os模块-File文件读操作 这里结束和 File
结构体相关的文件读操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 package mainimport ( "fmt" "os" ) func openCloseFile () { f, _ := os.Open("a.txt" ) fmt.Printf("f.Name(): %v\n" , f.Name()) f2, _ := os.OpenFile("a1.txt" , os.O_RDWR|os.O_CREATE, 0755 ) fmt.Printf("f2.Name(): %v\n" , f2.Name()) err := f.Close() fmt.Printf("err: %v\n" , err) err2 := f2.Close() fmt.Printf("err2: %v\n" , err2) } func createFile () { f, _ := os.Create("a2.txt" ) fmt.Printf("f.Name(): %v\n" , f.Name()) f2, _ := os.CreateTemp("" , "temp" ) fmt.Printf("f2.Name(): %v\n" , f2.Name()) } func readOps () { f, _ := os.Open("a.txt" ) f.Seek(3 , 0 ) buf := make ([]byte , 10 ) n, _ := f.Read(buf) fmt.Printf("n: %v\n" , n) fmt.Printf("string(buf): %v\n" , string (buf)) f.Close() } func main () { readOps() }
Golang标准库os模块-File文件写操作 这里结束和 File
结构体相关的文件写操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 package mainimport ( "fmt" "os" ) func openCloseFile () { f, _ := os.Open("a.txt" ) fmt.Printf("f.Name(): %v\n" , f.Name()) f2, _ := os.OpenFile("a1.txt" , os.O_RDWR|os.O_CREATE, 0755 ) fmt.Printf("f2.Name(): %v\n" , f2.Name()) err := f.Close() fmt.Printf("err: %v\n" , err) err2 := f2.Close() fmt.Printf("err2: %v\n" , err2) } func createFile () { f, _ := os.Create("a2.txt" ) fmt.Printf("f.Name(): %v\n" , f.Name()) f2, _ := os.CreateTemp("" , "temp" ) fmt.Printf("f2.Name(): %v\n" , f2.Name()) } func readOps () { f, _ := os.Open("a.txt" ) f.Seek(3 , 0 ) buf := make ([]byte , 10 ) n, _ := f.Read(buf) fmt.Printf("n: %v\n" , n) fmt.Printf("string(buf): %v\n" , string (buf)) f.Close() } func main () { readOps() }
Golang标准库os包进程相关操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package mainimport ( "fmt" "os" "time" ) func main () { fmt.Printf("os.Getpid(): %v\n" , os.Getpid()) fmt.Printf("os.Getppid(): %v\n" , os.Getppid()) attr := &os.ProcAttr{ Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, Env: os.Environ(), } p, err := os.StartProcess("C:\\Windows\\System32\\notepad.exe" , []string {"C:\\Windows\\System32\\notepad.exe" , "D:\\a.txt" }, attr) if err != nil { fmt.Println(err) } fmt.Println(p) fmt.Println("进程ID:" , p.Pid) p2, _ := os.FindProcess(p.Pid) fmt.Println(p2) time.AfterFunc(time.Second*10 , func () { p.Signal(os.Kill) }) ps, _ := p.Wait() fmt.Println(ps.String()) }
Golang标准库os包和环境相关的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package mainimport ( "fmt" "os" ) func main () { s := os.Environ() fmt.Printf("s: %v\n" , s) s2 := os.Getenv("GOPATH" ) fmt.Printf("s2: %v\n" , s2) os.Setenv("env1" , "env1" ) s2 = os.Getenv("aaa" ) fmt.Printf("s2: %v\n" , s2) fmt.Println("-----------" ) s3, b := os.LookupEnv("env1" ) fmt.Printf("b: %v\n" , b) fmt.Printf("s3: %v\n" , s3) os.Setenv("NAME" , "gopher" ) os.Setenv("BURROW" , "/usr/gopher" ) fmt.Println(os.ExpandEnv("$NAME lives in ${BURROW}." )) }
Golang标准库io包 Go 语言中,为了方便开发者使用,将 IO 操作封装在了如下几个包中:
io 为 IO 原语(I/O primitives)提供基本的接口 os File Reader Writer
io/ioutil 封装一些实用的 I/O 函数
fmt 实现格式化 I/O,类似 C 语言中的 printf 和 scanf format fmt
bufio 实现带缓冲I/O
io — 基本的 IO 接口 在 io 包中最重要的是两个接口:Reader 和 Writer 接口。本章所提到的各种 IO 包,都跟这两个接口有关,也就是说,只要实现了这两个接口,它就有了 IO 的功能
Reader 接口 1 2 3 type Reader interface { Read(p []byte ) (n int , err error) }
Writer 接口 1 2 3 type Writer interface { Write(p []byte ) (n int , err error) }
那些类型实现了Reader和Writer接口 1 2 3 4 5 6 7 8 9 os.File 同时实现了 io.Reader 和 io.Writer strings.Reader 实现了 io.Reader bufio.Reader/Writer 分别实现了 io.Reader 和 io.Writer bytes.Buffer 同时实现了 io.Reader 和 io.Writer bytes.Reader 实现了 io.Reader compress/gzip.Reader/Writer 分别实现了 io.Reader 和 io.Writer crypto/cipher.StreamReader/StreamWriter 分别实现了 io.Reader 和 io.Writer crypto/tls.Conn 同时实现了 io.Reader 和 io.Writer encoding/csv.Reader/Writer 分别实现了 io.Reader 和 io.Writer
Golang标准库ioutil包 封装一些实用的 I/O 函数
名称
作用
ReadAll
读取数据,返回读到的字节 slice
ReadDir
读取一个目录,返回目录入口数组 []os.FileInfo
ReadFile
读一个文件,返回文件内容(字节slice)
WriteFile
根据文件路径,写入字节slice
TempDir
在一个目录中创建指定前缀名的临时目录,返回新临时目录的路径
TempFile
在一个目录中创建指定前缀名的临时文件,返回 os.File
Golang标准库fmt包 fmt包实现了格式化的I/O函数,这点类似C语言中的printf和scanf,但是更加简单. format
Scanning 一组类似的函数通过扫描已格式化的文本来产生值。
Scan、Scanf 和 Scanln 从os.Stdin 中读取;
Fscan、Fscanf 和 Fscanln 从指定的 io.Reader 中读取;
Sscan、Sscanf 和 Sscanln 从实参字符串中读取。
Scanln、Fscanln 和 Sscanln在换行符处停止扫描,且需要条目紧随换行符之后;
Scanf、Fscanf 和 Sscanf需要输入换行符来匹配格式中的换行符;其它函数则将换行符视为空格。
Scanf、Fscanf 和 Sscanf 根据格式字符串解析实参,类似于 Printf。例如,%x会将一个整数扫描为十六进制数,而 %v 则会扫描该值的默认表现格式。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport "fmt" func test1 () { var age int fmt.Println("请输入年龄:" ) fmt.Scan(&age) fmt.Printf("age: %v\n" , age) } func test2 () { var name string fmt.Println("请输入姓名:" ) fmt.Scanf("%s" , &name) fmt.Printf("name: %v\n" , name) } func test3 () { var age int fmt.Println("请输入年龄:" ) fmt.Scanln(&age) fmt.Printf("age: %v\n" , age) } func main () { test3() }
其他实例参考官网
函数 1 func Errorf (format string , a ...interface {}) error
Errorf
根据于格式说明符进行格式化,并将字符串作为满足 error 的值返回,其返回类型是error.
1 func Fprint (w io.Writer, a ...interface {}) (n int , err error)
Fprint
使用其操作数的默认格式进行格式化并写入到 w。当两个连续的操作数均不为字符串时,它们之间就会添加空格。它返回写入的字节数以及任何遇到的错误。
1 func Fprintf (w io.Writer, format string , a ...interface {}) (n int , err error) //
Fprintf
根据于格式说明符进行格式化并写入到 w。它返回写入的字节数以及任何遇到的写入错误。
1 func Fprintln (w io.Writer, a ...interface {}) (n int , err error)
Fprintln
使用其操作数的默认格式进行格式化并写入到 w。其操作数之间总是添加空格,且总在最后追加一个换行符。它返回写入的字节数以及任何遇到的错误。
实例
参考官网文档
Golang标准库bufio bufio
bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。
常量 1 2 3 const ( defaultBufSize = 4096 )
变量 1 2 3 4 5 6 var ( ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte" ) ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune" ) ErrBufferFull = errors.New("bufio: buffer full" ) ErrNegativeCount = errors.New("bufio: negative count" ) )
1 2 3 4 5 var ( ErrTooLong = errors.New("bufio.Scanner: token too long" ) ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count" ) ErrAdvanceTooFar = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input" ) )
会被Scanner类型返回的错误。
type Reader 1 2 3 4 5 6 7 8 type Reader struct { buf []byte rd io.Reader r, w int err error lastByte int lastRuneSize int }
Reader实现了给一个io.Reader接口对象附加缓冲。
func NewReader 1 func NewReader (rd io.Reader) *Reader
NewReader创建一个具有默认大小缓冲、从r读取的*Reader。NewReader 相当于 NewReaderSize(rd, 4096)
func NewReaderSize 1 func NewReaderSize (rd io.Reader, size int ) *Reader
NewReaderSize创建一个具有最少有size尺寸的缓冲、从r读取的Reader。如果参数r已经是一个具有足够大缓冲的 Reader类型值,会返回r。
func (*Reader)Reset(r io.Reader) 1 func (b *Reader) Reset (r io.Reader)
Reset丢弃缓冲中的数据,清除任何错误,将b重设为其下层从r读取数据。
1 2 3 4 5 6 7 8 9 10 func main () { s := strings.NewReader("ABCEFG" ) str := strings.NewReader("123455" ) br := bufio.NewReader(s) b, _ := br.ReadString('\n' ) fmt.Println(b) br.Reset(str) b, _ = br.ReadString('\n' ) fmt.Println(b) }
func (*Reader)Read 1 func (b *Reader) Read (p []byte ) (n int , err error)
Read读取数据写入p。本方法返回写入p的字节数。本方法一次调用最多会调用下层Reader接口一次Read方法,因此返回值n可能小于len(p)。读取到达结尾时,返回值n将为0而err将为io.EOF。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func main () { s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" ) br := bufio.NewReader(s) p := make ([]byte , 10 ) for { n, err := br.Read(p) if err == io.EOF { break } else { fmt.Printf("string(p): %v\n" , string (p[0 :n])) } } }
func (*Reader)ReadByte 1 func (b *Reader) ReadByte () (c byte , err error)
ReadByte读取并返回一个字节。如果没有可用的数据,会返回错误。
func (*Reader)UnreadByte 1 func (b *Reader) UnreadByte () error
UnreadByte吐出最近一次读取操作读取的最后一个字节。(只能吐出最后一个,多次调用会出问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func main () { s := strings.NewReader("ABCDEFG" ) br := bufio.NewReader(s) c, _ := br.ReadByte() fmt.Printf("%c\n" , c) c, _ = br.ReadByte() fmt.Printf("%c\n" , c) br.UnreadByte() c, _ = br.ReadByte() fmt.Printf("%c\n" , c) }
func (*Reader)ReadRune 1 func (b *Reader) ReadRune () (r rune , size int , err error)
ReadRune读取一个utf-8编码的unicode码值,返回该码值、其编码长度和可能的错误。如果utf-8编码非法,读取位置只移动1字节,返回U+FFFD,返回值size为1而err为nil。如果没有可用的数据,会返回错误。
func (*Reader)UnreadRune 1 func (b *Reader) UnreadRune () error
UnreadRune吐出最近一次ReadRune调用读取的unicode码值。如果最近一次读取不是调用的ReadRune,会返回错误。(从这点看,UnreadRune比UnreadByte严格很多)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func main () { s := strings.NewReader ("你好,世界!" ) br := bufio.NewReader (s) c, size, _ := br.ReadRune () fmt.Printf ("%c %v\n" , c, size) c, size, _ = br.ReadRune () fmt.Printf ("%c %v\n" , c, size) br.UnreadRune () c, size, _ = br.ReadRune () fmt.Printf ("%c %v\n" , c, size) }
func (*Reader)ReadLine 1 func (b *Reader) ReadLine () (line []byte , isPrefix bool , err error)
ReadLine是一个低水平的行数据读取原语。大多数调用者应使用ReadBytes(‘\n’)或ReadString(‘\n’)代替,或者使用Scanner。
ReadLine尝试返回一行数据,不包括行尾标志的字节。如果行太长超过了缓冲,返回值isPrefix会被设为true,并返回行的前面一部分。该行剩下的部分将在之后的调用中返回。返回值isPrefix会在返回该行最后一个片段时才设为false。返回切片是缓冲的子切片,只在下一次读取操作之前有效。ReadLine要么返回一个非nil的line,要么返回一个非nil的err,两个返回值至少一个非nil。
返回的文本不包含行尾的标志字节(”\r\n”或”\n”)。如果输入流结束时没有行尾标志字节,方法不会出错,也不会指出这一情况。在调用ReadLine之后调用UnreadByte会总是吐出最后一个读取的字节(很可能是该行的行尾标志字节),即使该字节不是ReadLine返回值的一部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func main () { s := strings.NewReader ("ABC\nDEF\r\nGHI\r\nGHI" ) br := bufio.NewReader (s) w, isPrefix, _ := br.ReadLine () fmt.Printf ("%q %v\n" , w, isPrefix) w, isPrefix, _ = br.ReadLine () fmt.Printf ("%q %v\n" , w, isPrefix) w, isPrefix, _ = br.ReadLine () fmt.Printf ("%q %v\n" , w, isPrefix) w, isPrefix, _ = br.ReadLine () fmt.Printf ("%q %v\n" , w, isPrefix) }
func (*Reader)ReadSlice 1 func (b *Reader) ReadSlice (delim byte ) (line []byte , err error)
ReadSlice读取直到第一次遇到delim字节,返回缓冲里的包含已读取的数据和delim字节的切片。该返回值只在下一次读取操作之前合法。如果ReadSlice放在在读取到delim之前遇到了错误,它会返回在错误之前读取的数据在缓冲中的切片以及该错误(一般是io.EOF)。如果在读取到delim之前缓冲就被写满了,ReadSlice失败并返回ErrBufferFull。因为ReadSlice的返回值会被下一次I/O操作重写,调用者应尽量使用ReadBytes或ReadString替代本法功法。当且仅当ReadBytes方法返回的切片不以delim结尾时,会返回一个非nil的错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { s := strings.NewReader ("ABC,DEF,GHI,JKL" ) br := bufio.NewReader (s) w, _ := br.ReadSlice (',' ) fmt.Printf ("%q\n" , w) w, _ = br.ReadSlice (',' ) fmt.Printf ("%q\n" , w) w, _ = br.ReadSlice (',' ) fmt.Printf ("%q\n" , w) }
func (*Reader)ReadBytes 1 func (b *Reader) ReadBytes (delim byte ) (line []byte , err error)
ReadBytes读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的切片。如果ReadBytes方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadBytes方法返回的切片不以delim结尾时,会返回一个非nil的错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { s := strings.NewReader("ABC DEF GHI JKL" ) br := bufio.NewReader(s) w, _ := br.ReadBytes(' ' ) fmt.Printf("%q\n" , w) w, _ = br.ReadBytes(' ' ) fmt.Printf("%q\n" , w) w, _ = br.ReadBytes(' ' ) fmt.Printf("%q\n" , w) }
func (*Reader)ReadString 1 func (b *Reader) ReadString (delim byte ) (line string , err error)
ReadString读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的字符串。如果ReadString方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadString方法返回的切片不以delim结尾时,会返回一个非nil的错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { s := strings.NewReader("ABC DEF GHI JKL" ) br := bufio.NewReader(s) w, _ := br.ReadString(' ' ) fmt.Printf("%q\n" , w) w, _ = br.ReadString(' ' ) fmt.Printf("%q\n" , w) w, _ = br.ReadString(' ' ) fmt.Printf("%q\n" , w) }
func (*Reader)WriteTo 1 func (b *Reader) WriteTo (w io.Writer) (n int64 , err error)
WriteTo方法实现了io.WriterTo接口。
1 2 3 4 5 6 7 8 func main () { s := strings.NewReader("ABCEFGHIJKLMN" ) br := bufio.NewReader(s) b := bytes.NewBuffer(make ([]byte , 0 )) br.WriteTo(b) fmt.Printf("%s\n" , b) }
type Writer 1 2 3 4 5 6 type Writer struct { err error buf []byte n int wr io.Writer }
Writer实现了为io.Writer接口对象提供缓冲。如果在向一个Writer类型值写入时遇到了错误,该对象将不再接受任何数据,且所有写操作都会返回该错误。在说有数据都写入后,调用者有义务调用Flush方法以保证所有的数据都交给了下层的io.Writer。
func NewWriter 1 func NewWriter (w io.Writer) *Writer
NewWriter创建一个具有默认大小缓冲、写入w的*Writer。NewWriter 相当于 NewWriterSize(wr, 4096)
func NewWriterSize 1 func NewWriterSize (w io.Writer, size int ) *Writer
NewWriterSize创建一个具有最少有size尺寸的缓冲、写入w的Writer。如果参数w已经是一个具有足够大缓冲的 Writer类型值,会返回w。
func (*Writer)Reset 1 func (b *Writer) Reset (w io.Writer)
Reset丢弃缓冲中的数据,清除任何错误,将b重设为将其输出写入w。
1 2 3 4 5 6 7 8 9 10 11 func main () { b := bytes.NewBuffer(make ([]byte , 0 )) bw := bufio.NewWriter(b) bw.WriteString("123456789" ) c := bytes.NewBuffer(make ([]byte , 0 )) bw.Reset(c) bw.WriteString("456" ) bw.Flush() fmt.Println(b) fmt.Println(c) }
func (*Writer)Bufferd 1 func (b *Writer) Buffered () int
Buffered返回缓冲中已使用的字节数。
func (*Writer)Available 1 func (b *Writer) Available () int
Available返回缓冲中还有多少字节未使用。
func (*Writer) Write 1 func (b *Writer) Write (p []byte ) (nn int , err error)
Write将p的内容写入缓冲。返回写入的字节数。如果返回值nn < len(p),还会返回一个错误说明原因。
func (*Writer) WriteString 1 func (b *Writer) WriteString (s string ) (int , error)
WriteString写入一个字符串。返回写入的字节数。如果返回值nn < len(s),还会返回一个错误说明原因。
func (*Writer) WriteByte 1 func (b *Writer) WriteByte (c byte ) error
WriteByte写入单个字节。
func (*Writer) WriteRune 1 func (b *Writer) WriteRune (r rune ) (size int , err error)
WriteRune写入一个unicode码值(的utf-8编码),返回写入的字节数和可能的错误。
func (*Writer) Flush 1 func (b *Writer) Flush () error
Flush方法将缓冲中的数据写入下层的io.Writer接口。
func (*Writer) ReadFrom 1 func (b *Writer) ReadFrom (r io.Reader) (n int64 , err error)
ReadFrom实现了io.ReaderFrom接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func main () { b := bytes.NewBuffer(make ([]byte , 0 )) bw := bufio.NewWriter(b) fmt.Println(bw.Available()) fmt.Println(bw.Buffered()) bw.WriteString("ABCDEFGHIJKLMN" ) fmt.Println(bw.Available()) fmt.Println(bw.Buffered()) fmt.Printf("%q\n" , b) bw.Flush() fmt.Println(bw.Available()) fmt.Println(bw.Buffered()) fmt.Printf("%q\n" , b) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func main () { b := bytes.NewBuffer(make ([]byte , 0 )) bw := bufio.NewWriter(b) bw.WriteByte('H' ) bw.WriteByte('e' ) bw.WriteByte('l' ) bw.WriteByte('l' ) bw.WriteByte('o' ) bw.WriteByte(' ' ) bw.WriteRune('世' ) bw.WriteRune('界' ) bw.WriteRune('!' ) bw.Flush() fmt.Println(b) }
1 2 3 4 5 6 7 8 func main () { b := bytes.NewBuffer(make ([]byte , 0 )) s := strings.NewReader("Hello 世界!" ) bw := bufio.NewWriter(b) bw.ReadFrom(s) fmt.Println(b) }
type ReadWriter 1 2 3 4 type ReadWriter struct { *Reader *Writer }
ReadWriter类型保管了指向Reader和Writer类型的指针,(因此)实现了io.ReadWriter接口。
func NewReadWriter 1 func NewReadWriter (r *Reader, w *Writer) *ReadWriter
NewReadWriter申请创建一个新的、将读写操作分派给r和w 的ReadWriter。
1 2 3 4 5 6 7 8 9 10 11 12 func main () { b := bytes.NewBuffer(make ([]byte , 0 )) bw := bufio.NewWriter(b) s := strings.NewReader("123" ) br := bufio.NewReader(s) rw := bufio.NewReadWriter(br, bw) p, _ := rw.ReadString('\n' ) fmt.Println(string (p)) rw.WriteString("asdf" ) rw.Flush() fmt.Println(b) }
type SplitFunc 1 type SplitFunc func (data []byte , atEOF bool ) (advance int , token []byte , err error)
SplitFunc类型代表用于对输出作词法分析的分割函数。
参数data是尚未处理的数据的一个开始部分的切片,参数atEOF表示是否Reader接口不能提供更多的数据。返回值是解析位置前进的字节数,将要返回给调用者的token切片,以及可能遇到的错误。如果数据不足以(保证)生成一个完整的token,例如需要一整行数据但data里没有换行符,SplitFunc可以返回(0, nil, nil)来告诉Scanner读取更多的数据写入切片然后用从同一位置起始、长度更长的切片再试一次(调用SplitFunc类型函数)。
如果返回值err非nil,扫描将终止并将该错误返回给Scanner的调用者。
除非atEOF为真,永远不会使用空切片data调用SplitFunc类型函数。然而,如果atEOF为真,data却可能是非空的、且包含着未处理的文本。
SplitFunc 的作用很简单,从 data 中找出你感兴趣的数据,然后返回并告诉调用者,data 中有多少数据你已经处理过了
func ScanBytes 1 func ScanBytes (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanBytes是用于Scanner类型的分割函数(符合SplitFunc),本函数会将每个字节作为一个token返回。
func ScanRunes 1 func ScanRunes (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanRunes是用于Scanner类型的分割函数(符合SplitFunc),本函数会将每个utf-8编码的unicode码值作为一个token返回。本函数返回的rune序列和range一个字符串的输出rune序列相同。错误的utf-8编码会翻译为U+FFFD = “\xef\xbf\xbd”,但只会消耗一个字节。调用者无法区分正确编码的rune和错误编码的rune。
func ScanWords 1 func ScanWords (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanRunes是用于Scanner类型的分割函数(符合SplitFunc),本函数会将空白(参见unicode.IsSpace)分隔的片段(去掉前后空白后)作为一个token返回。本函数永远不会返回空字符串。用来找出 data 中的单行数据并返回(包括空行)
func ScanLines 1 func ScanLines (data []byte , atEOF bool ) (advance int , token []byte , err error)
ScanLines是用于Scanner类型的分割函数(符合SplitFunc),本函数会将每一行文本去掉末尾的换行标记作为一个token返回。返回的行可以是空字符串。换行标记为一个可选的回车后跟一个必选的换行符。最后一行即使没有换行符也会作为一个token返回。
type Scanner 1 2 3 4 5 6 7 8 9 10 type Scanner struct { r io.Reader split SplitFunc maxTokenSize int token []byte buf []byte start int end int err error }
Scanner类型提供了方便的读取数据的接口,如从换行符分隔的文本里读取每一行。成功调用的Scan方法会逐步提供文件的token,跳过token之间的字节。token由SplitFunc类型的分割函数指定;默认的分割函数会将输入分割为多个行,并去掉行尾的换行标志。本包预定义的分割函数可以将文件分割为行、字节、unicode码值、空白分隔的word。调用者可以定制自己的分割函数。扫描会在抵达输入流结尾、遇到的第一个I/O错误、token过大不能保存进缓冲时,不可恢复的停止。当扫描停止后,当前读取位置可能会远在最后一个获得的token后面。需要更多对错误管理的控制或token很大,或必须从reader连续扫描的程序,应使用bufio.Reader代替。
func NewScanner 1 func NewScanner (r io.Reader) *Scanner
NewScanner创建并返回一个从r读取数据的Scanner,默认的分割函数是ScanLines。
func (*Scanner) Split 1 func (s *Scanner) Split (split SplitFunc)
Split设置该Scanner的分割函数。本方法必须在Scan之前调用。
1 2 3 4 5 6 7 8 func main () { s := strings.NewReader("ABC DEF GHI JKL" ) bs := bufio.NewScanner(s) bs.Split(bufio.ScanWords) for bs.Scan() { fmt.Println(bs.Text()) } }
func (*Scanner) Scan 1 func (s *Scanner) Scan () bool
Scan方法获取当前位置的token(该token可以通过Bytes或Text方法获得),并让Scanner的扫描位置移动到下一个token。当扫描因为抵达输入流结尾或者遇到错误而停止时,本方法会返回false。在Scan方法返回false后,Err方法将返回扫描时遇到的任何错误;除非是io.EOF,此时Err会返回nil。
1 2 3 4 5 6 7 8 func main () { s := strings.NewReader("Hello 世界!" ) bs := bufio.NewScanner(s) bs.Split(bufio.ScanBytes) for bs.Scan() { fmt.Printf("%s " , bs.Text()) } }
func (*Scanner) Bytes 1 func (s *Scanner) Bytes () []byte
Bytes方法返回最近一次Scan调用生成的token。底层数组指向的数据可能会被下一次Scan的调用重写。
1 2 3 4 5 6 7 8 func main () { s := strings.NewReader("Hello 世界!" ) bs := bufio.NewScanner(s) bs.Split(bufio.ScanRunes) for bs.Scan() { fmt.Printf("%s " , bs.Text()) } }
func (*Scanner) Text 1 func (s *Scanner) Text () string
Bytes方法返回最近一次Scan调用生成的token,会申请创建一个字符串保存token并返回该字符串。
func (*Scanner) Err 1 func (s *Scanner) Err () error
Err返回Scanner遇到的第一个非EOF的错误。
Golang标准库log log简介 Golang内置了 log
包,实现简单的日志服务。通过调用 log
包的函数,可以实现简单的日志打印功能。
log使用 log
包中有3个系列的日志打印函数,分别 print
系列、panic
系列、fatal
系列。
函数系列
作用
print
单纯打印日志
panic
打印日志,抛出panic异常
fatal
打印日志,强制结束程序(os.Exit(1)),defer
函数不会执行
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport ( "fmt" "log" ) func main () { defer fmt.Println("发生了 panic错误!" ) log.Print("my log" ) log.Printf("my log %d" , 100 ) name := "tom" age := 20 log.Println(name, "," , age) log.Panic("致命错误!" ) fmt.Println("end..." ) }
结果示例(实际结果不是这样的哦,因为panic,fatal会影响程序的执行):
1 2 3 4 5 6 7 8 9 10 11 12 13 2021 /11 /29 16 :45 :59 my log2021 /11 /29 16 :45 :59 my log 100 2021 /11 /29 16 :45 :59 tom , 20 2021 /11 /29 16 :45 :59 致命错误!发生了 panic 错误! panic : 致命错误!goroutine 1 [running]: log.Panic({0xc000107f00 , 0x3 , 0xc000107f00 }) C:/Program Files/Go/src/log/log.go :354 +0x65 main.main() c:/Users/52406 /Desktop/golangprojects/xiaobaibk.com/pro01/demo.go :15 +0x19e exit status 2
log配置 标准log配置 默认情况下log只会打印出时间,但是实际情况下我们可能还需要获取文件名,行号等信息,log
包提供给我们定制的接口。 log
包提供两个标准log配置的相关方法:
1 2 func Flags() int // 返回标准log输出配置 func SetFlags(flag int) // 设置标准log输出配置
flag参数 1 2 3 4 5 6 7 8 9 10 11 const ( // 控制输出日志信息的细节,不能控制输出的顺序和格式。 // 输出的日志在每一项后会有一个冒号分隔:例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message Ldate = 1 << iota // 日期:2009/01/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的初始值 )
标准日志配置示例 1 2 3 4 5 6 7 8 9 10 11 12 13 package mainimport ( "fmt" "log" ) func main () { i := log.Flags() fmt.Printf("i: %v\n" , i) log.SetFlags(log.Ldate | log.Ltime | log.Llongfile) log.Print("my log" ) }
输出结果:
1 2 i: 3 2021/11/29 16:49:53 c:/Users/52406/Desktop/golangprojects/xiaobaibk.com/pro01/demo.go:12: my log
日志前缀配置 log
包提供两个日志前缀配置的相关函数:
1 2 func Prefix () string // 返回日志的前缀配置func SetPrefix (prefix string ) // 设置日志前缀
日志前缀配置实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "fmt" "log" ) func main () { s := log.Prefix() fmt.Printf("s: %v\n" , s) log.SetPrefix("MyLog: " ) s = log.Prefix() fmt.Printf("s: %v\n" , s) log.Print("my log..." ) }
输出结果:
1 2 3 s: s: MyLog: MyLog: 2021/11/29 16:51:55 my log...
日志输出位置配置 前面介绍的都是将日志输出到控制台上,golang的 log
包还支持将日志输出到文件中。log
包提供了 func SetOutput(w io.Writer)
函数,将日志输出到文件中。
日志输出位置配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "log" "os" ) func main () { f, err := os.OpenFile("a.log" , os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644 ) if err != nil { log.Panic("打开日志文件异常" ) } log.SetOutput(f) log.Print("my log..." ) }
结果: 日志输出到当前目录下a.log文件中
1 2021/11/29 16:57:13 my log...
自定义logger log
包为我们提供了内置函数,让我们能自定义logger。从效果上来看,就是将标题3中的标准日志配置、日志前缀配置、日志输出位置配置整合到一个函数中,使日志配置不在那么繁琐。 log
包中提供了 func New(out io.Writer, prefix string, flag int) *Logger
函数来实现自定义logger。
示例 1 2 3 4 5 6 7 8 9 10 11 12 var logger *log.Loggerfunc init () { logFile, err := os.OpenFile("a.log" , os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644 ) if err != nil { log.Panic("打开日志文件异常" ) } logger = log.New(logFile, "success" , log.Ldate | log.Ltime | log.Lshortfile) } func main () { logger.Println("自定义logger" ) }
Golang标准库builtin 这个包提供了一些类型声明、变量和常量声明,还有一些便利函数,这个包不需要导入,这些变量和函数就可以直接使用。
常用函数 append 1 2 3 4 func append (slice []Type, elems ...Type) []Type slice = append (slice, elem1, elem2) slice = append (slice, anotherSlice...)
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package mainimport "fmt" func main () { s1 := []int {1 , 2 , 3 } i := append (s1, 4 ) fmt.Printf("i: %v\n" , i) s2 := []int {7 , 8 , 9 } i2 := append (s1, s2...) fmt.Printf("i2: %v\n" , i2) }
len 返回,数组、切片、字符串、通道的长度
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package mainimport "fmt" func main () { s1 := "hello world" i := len (s1) fmt.Printf("i: %v\n" , i) s2 := []int {1 , 2 , 3 } fmt.Printf("len(s2): %v\n" , len (s2)) }
print、println 打印输出到控制台。
实例 1 2 3 4 5 6 7 8 9 10 11 package mainimport "fmt" func main () { name := "tom" age := 20 print (name, " " , age, "\n" ) fmt.Println("----------" ) println (name, " " , age) }
panic 抛出一个panic异常
实例 1 2 3 4 5 6 7 8 9 package mainimport "fmt" func main () { defer fmt.Println("panic 异常后执行..." ) panic ("panic 错误..." ) fmt.Println("end..." ) }
new和make new
和 make
区别:
make
只能用来分配及初始化 类型为slice
,map
,chan
的数据;new
可以分配任意类型的数据
new
分配返回的是指针,即类型*T
;make
返回引用,即T
;
new
分配的空间被清零,make
分配后,会进行初始化 。
实例 new
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func testNew () { b := new (bool ) fmt.Println(*b) i := new (int ) fmt.Println(*i) s := new (string ) fmt.Println(*s) } func main () { testNew() } 运行结果: false 0 ""
make
内建函数make(T, args)与new(T)的用途不一样。它只用来创建slice,map和channel,并且返回一个初始化的(而不是置零),类型为T的值(而不是*T)。之所以有所不同,是因为这三个类型的背后引用了使用前必须初始化的数据结构。例如,slice是一个三元描述符,包含一个指向数据(在数组中)的指针,长度,以及容量,在这些项被初始化之前,slice都是nil的。对于slice,map和channel,make初始化这些内部数据结构,并准备好可用的值。
分配一个有100个int的数组,然后创建一个长度为10,容量为100的slice结构,该slice引用包含前10个元素的数组。对应的,new([]int)返回一个指向新分配的,被置零的slice结构体的指针,即指向值为nil的slice的指针。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var p *[]int = new ([]int ) var v []int = make ([]int , 100 ) var p *[]int = new ([]int )*p = make ([]int , 100 , 100 ) v := make ([]int , 100 ) 运行结果: p: &[] v: [0 0 0 0 0 0 0 0 0 0 ]
Golang标准库bytes bytes包提供了对字节切片 进行读写操作的一系列函数,字节切片处理的函数比较多分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等.
常用函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package mainimport ( "bytes" "fmt" ) func main () { var i int = 1 var j byte = 2 j = byte (i) fmt.Printf("j: %v\n" , j) b := []byte ("xiaobaibk.com" ) sublice1 := []byte ("xiaobaibk" ) sublice2 := []byte ("Xiaobaibk" ) fmt.Println(bytes.Contains(b, sublice1)) fmt.Println(bytes.Contains(b, sublice2)) s := []byte ("hellooooooooo" ) sep1 := []byte ("h" ) sep2 := []byte ("l" ) sep3 := []byte ("o" ) fmt.Println(bytes.Count(s, sep1)) fmt.Println(bytes.Count(s, sep2)) fmt.Println(bytes.Count(s, sep3)) b = []byte ("hi" ) fmt.Println(string (bytes.Repeat(b, 1 ))) fmt.Println(string (bytes.Repeat(b, 3 ))) s = []byte ("hello,world" ) old := []byte ("o" ) news := []byte ("ee" ) fmt.Println(string (bytes.Replace(s, old, news, 0 ))) fmt.Println(string (bytes.Replace(s, old, news, 1 ))) fmt.Println(string (bytes.Replace(s, old, news, 2 ))) fmt.Println(string (bytes.Replace(s, old, news, -1 ))) s = []byte ("你好世界" ) r := bytes.Runes(s) fmt.Println("转换前字符串的长度: " , len (s)) fmt.Println("转换后字符串的长度: " , len (r)) s2 := [][]byte {[]byte ("你好" ), []byte ("世界" )} sep4 := []byte ("," ) fmt.Println(string (bytes.Join(s2, sep4))) sep5 := []byte ("#" ) fmt.Println(string (bytes.Join(s2, sep5))) }
Buffer类型 缓冲区是具有读取和写入方法的可变大小的字节缓冲区。Buffer 的零值是准备使用的空缓冲区。
声明一个Buffer的四种方法:
1 2 3 4 var b bytes.Buffer b := new (bytes.Buffer) b := bytes.NewBuffer(s []byte ) b := bytes.NewBufferString(s string )
往Buffer中写入数据
1 2 3 4 5 b.Write(d []byte ) b.WriteString(s string ) b.WriteByte(c byte ) b.WriteRune(r rune ) b.WriteTo(w io.Writer)
注:将文件中的内容写入Buffer,则使用ReadForm(i io.Reader)
从Buffer中读取数据到指定容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 c := make ([]byte ,8 ) b.Read(c) b.ReadByte() b.ReadRune() b.ReadBytes(delimiter byte ) b.ReadString(delimiter byte ) file, _ := os.Open(".text.txt" ) buf := bytes.NewBufferString("Hello world" ) buf.ReadFrom(file) fmt.Println(buf.String()) 清空数据 b.Reset() 转换为字符串 b.String()
Reader类型 Reader实现了 io.Reader, io.ReaderAt, io.WriterTo, io.Seeker,io.ByteScanner, io.RuneScanner
接口,Reader是只读的、可以seek。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 func testReader () { data := "123456789" re := bytes.NewReader([]byte (data)) fmt.Println("re len : " , re.Len()) fmt.Println("re size : " , re.Size()) fmt.Println("------------" ) buf := make ([]byte , 2 ) for { n, err := re.Read(buf) if err != nil { break } fmt.Println(string (buf[:n])) } fmt.Println("------------" ) re.Seek(0 , 0 ) for { b, err := re.ReadByte() if err != nil { break } fmt.Println(string (b)) } fmt.Println("------------" ) re.Seek(0 , 0 ) off := int64 (0 ) for { n, err := re.ReadAt(buf, off) if err != nil { break } off += int64 (n) fmt.Println(off, string (buf[:n])) } }
Golang标准库errors errors包实现了操作错误的函数。语言使用 error 类型来返回函数执行过程中遇到的错误,如果返回的 error 值为 nil
,则表示未遇到错误,否则 error 会返回一个字符串,用于说明遇到了什么错误。
error 结构 1 2 3 type error interface { Error() string }
你可以用任何类型去实现它(只要添加一个 Error() 方法即可),也就是说,error 可以是任何类型,这意味着,函数返回的 error 值实际可以包含任意信息,不一定是字符串。
error 不一定表示一个错误,它可以表示任何信息,比如 io 包中就用 error 类型的 io.EOF
表示数据读取结束,而不是遇到了什么错误。
errors 包实现了一个最简单的 error 类型,只包含一个字符串,它可以记录大多数情况下遇到的错误信息。errors 包的用法也很简单,只有一个 New
函数,用于生成一个最简单的 error 对象:
1 func New (text string ) error
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport ( "errors" "fmt" ) func check (s string ) error { if s == "" { return errors.New("字符串不能为空" ) } else { return nil } } func main () { check("hello" ) err := check("" ) fmt.Printf("err: %v\n" , err.Error()) }
自定义错误 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport ( "fmt" "time" ) 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) } }
Golang标准库中的sort包 sort包的内容,以及使用 sort包提供了排序切片和用户自定义数据集以及相关功能的函数。
sort包主要针对 []int
、[]float64
、[]string
、以及其他自定义切片 的排序。
结构体 1 2 3 type IntSlice []inttype Float64Slice type StringSlice
函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func Ints (a []int ) func IntsAreSorted (a []int ) bool func SearchInts (a []int , x int ) int func Float64s (a []float64 ) func Float64sAreSorted (a []float64 ) bool func SearchFloat64s (a []float64 , x float64 ) int func SearchFloat64s (a []flaot64, x float64 ) bool func Strings (a []string ) func StringsAreSorted (a []string ) bool func SearchStrings (a []string , x string ) int func Sort (data Interface) func Stable (data Interface) func Reverse (data Interface) Interface func ISSorted (data Interface) bool func Search (n int , f func (int ) bool ) int
接口 type Interface 1 2 3 4 5 type Interface interface { Len() int Less(i, j int ) bool Swap(i, j int ) }
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport ( "fmt" "sort" ) type NewInts []uint func (n NewInts) Len () int { return len (n) } func (n NewInts) Less (i, j int ) bool { fmt.Println(i, j, n[i] < n[j], n) return n[i] < n[j] } func (n NewInts) Swap (i, j int ) { n[i], n[j] = n[j], n[i] } func main () { n := []uint {1 ,3 ,2 } sort.Sort(NewInts(n)) fmt.Println(n) }
结构体 三种结构体的方法都是一样的,只是分别针对int切片、float64切片、strings切片这三种不同的类型。 然后三种结果都有五个公开方法
1 2 3 4 5 6 func (p xxxSlice) Len () int // 切片长度func (p xxxSlice) Less (i, j int ) bool func (p xxxSlice) Swap (i, j int ) func (p xxxSlice) Search (x xxx) int func (p xxxSlice) Sort ()
综合实例 []float64
:
1 2 3 4 f := []float64 {1.1 , 4.4 , 5.5 , 3.3 , 2.2 } sort.Float64s(f) fmt.Printf("f: %v\n" , f)
[]int:
1 2 3 4 f := []int {3 , 5 , 1 , 2 , 4 } sort.Ints(f) fmt.Printf("f: %v\n" , f)
string:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ls := sort.StringSlice{ "100" , "42" , "41" , "3" , "2" , } fmt.Println(ls) sort.Strings(ls) fmt.Println(ls) ls := sort.StringSlice{ "d" , "ac" , "c" , "ab" , "e" , } fmt.Println(ls) sort.Strings(ls) fmt.Println(ls) ls := sort.StringSlice{ "啊" , "博" , "次" , "得" , "饿" , "周" , } fmt.Println(ls) sort.Strings(ls) fmt.Println(ls) for _, v := range ls{ fmt.Println(v, []byte (v)) }
复杂结构:[][]int :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type testSlice [][]int func (l testSlice) Len () int { return len (l) }func (l testSlice) Swap (i, j int ) { l[i], l[j] = l[j], l[i] }func (l testSlice) Less (i, j int ) bool { return l[i][1 ] < l[j][1 ] }func main () { ls := testSlice{ {1 ,4 }, {9 ,3 }, {7 ,5 }, } fmt.Println(ls) sort.Sort(ls) fmt.Println(ls) }
复杂结构体:[]map[string]int [{"k":0},{"k1":1},{"k2":2] :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type testSlice []map [string ]float64 func (l testSlice) Len () int { return len (l) }func (l testSlice) Swap (i, j int ) { l[i], l[j] = l[j], l[i] }func (l testSlice) Less (i, j int ) bool { return l[i]["a" ] < l[j]["a" ] } func main () { ls := testSlice{ {"a" :4 , "b" :12 }, {"a" :3 , "b" :11 }, {"a" :5 , "b" :10 }, } fmt.Println(ls) sort.Sort(ls) fmt.Println(ls) }
复杂结构体:[]struct :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 type People struct { Name string Age int } type testSlice []Peoplefunc (l testSlice) Len () int { return len (l) }func (l testSlice) Swap (i, j int ) { l[i], l[j] = l[j], l[i] }func (l testSlice) Less (i, j int ) bool { return l[i].Age < l[j].Age }func main () { ls := testSlice{ {Name:"n1" , Age:12 }, {Name:"n2" , Age:11 }, {Name:"n3" , Age:10 }, } fmt.Println(ls) sort.Sort(ls) fmt.Println(ls) }
Golang标准库time time包提供测量和显示时间的功能。
基本使用 打印显示出现在的时间,基本示例如下。 其中now为 time.Time
类型,Month 为 time.Month
类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func test1 () { 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() fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n" , year, month, day, hour, minute, second) fmt.Printf("%T,%T,%T,%T,%T,%T,%T\n" , now, year, month, day, hour, minute, second) }
时间戳 在编程中对于时间戳的应用也尤为广泛,例如在Web开发中做cookies有效期,接口加密,Redis中的key有效期等等,大部分都是使用到了时间戳。
时间戳是自1970年1月1日(08:00:00GMT)至当前时间的总毫秒数。它也被称为Unix时间戳(UnixTimestamp)。 在GoLang中,获取时间戳的操作如下
1 2 3 4 5 func test2 () { now := time.Now() fmt.Printf("TimeStamp type:%T, TimeStamp:%v" , now.Unix(), now.Unix()) }
除此之外还有纳秒时间戳,我们可以使用 time.Now().UnixNano()
来获取它
1 2 3 4 5 func test3 () { now := time.Now() fmt.Printf("TimeStamp type:%T, TimeStamp:%v\n" , now.UnixNano(), now.UnixNano()) }
时间戳转化为普通的时间格式 在 go
语言中可以 time.Unix
来直接将时间戳转化为当前时间格式,实现瞬间替换。
1 2 3 4 5 6 7 8 9 10 11 12 func timeStampToTime () { timestamp := time.Now().Unix() timeObj := time.Unix(timestamp, 0 ) fmt.Println(timeObj) year := timeObj.Year() month := timeObj.Month() day := timeObj.Day() hour := timeObj.Hour() minute := timeObj.Minute() second := timeObj.Second() fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n" , year, month, day, hour, minute, second) }
操作时间 ADD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "fmt" "time" ) func add (h, m, s, mls, msc, ns time.Duration) { now := time.Now() fmt.Println(now.Add(time.Hour*h + time.Minute*m + time.Second*s + time.Millisecond*mls + time.Microsecond*msc + time.Nanosecond*ns)) } func main () { test4(3 , 4 , 5 , 6 , 7 , 8 ) }
注意在这里并不能增加年\月\日,仅能增加时分秒,也就是以下的才被允许
1 2 3 4 5 6 7 8 const ( Nanosecond Duration = 1 Microsecond = 1000 * Nanosecond Millisecond = 1000 * Microsecond Second = 1000 * Millisecond Minute = 60 * Second Hour = 60 * Minute )
Sub 1 2 3 4 5 6 func sub () { now := time.Now() targetTime := now.Add(time.Hour) fmt.Println(targetTime.Sub(now)) }
谁的sub谁为参照时间
Equal 1 func (t Time) Equal (u Time) bool
判断两个时间是否相同,会考虑时区的影响,因此不同时区标准的时间也可以正确比较。
Before 1 func (t Time) Before (u Time) bool
如果t代表的时间点在u之前,返回真;否则返回假。
After 1 func (t Time) After (u Time) bool
如果t代表的时间点在u之后,返回真;否则返回假。
定时器 使用 time.Tick(时间间隔)
来设置定时器,定时器的本质上是一个通道(channel)。
1 2 3 4 5 6 func tick () { ticker := time.Tick(time.Second) for i := range ticker { fmt.Println(i) } }
时间格式化 时间类型有一个自带的方法 Format
进行格式化,需要注意的是Go语言中格式化时间模板不是常见的 Y-m-d H:M:S
而是使用Go的诞生时间2006年1月2号15点04分(记忆口诀为2006 1 2 3 4)
1 2 3 4 5 6 7 8 9 10 11 func format () { now := time.Now() fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan" )) fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan" )) fmt.Println(now.Format("2006/01/02 15:04" )) fmt.Println(now.Format("15:04 2006/01/02" )) fmt.Println(now.Format("2006/01/02" )) }
补充:如果想格式化为12小时方式,需指定 PM
。
解析字符串格式的时间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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" , "2019/08/04 14:15:20" , loc) if err != nil { fmt.Println(err) return } fmt.Println(timeObj) fmt.Println(timeObj.Sub(now))
Golang 标准库encoding/json 这个包可以实现json的编码和解码,就是将json字符串转换为 struct
,或者将 struct
转换为json。
核心的两个函数 1 func Marshal (v interface {}) ([]byte , error)
将struct编码成json,可以接收任意类型
1 func Unmarshal (data []byte , v interface {}) error
将json转码成struct结构体
两个核心结构体 1 2 3 type Decoder struct { }
从输入流读取并解析json
1 2 3 type Encoder struct { }
写json到输出流
实例演示 结构体转换为json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 type Person struct { Name string Age int Email string } func Marshal () { p := Person{ Name: "tom" , Age: 20 , Email: "[email protected] " , } b, _ := json.Marshal(p) fmt.Printf("b: %v\n" , string (b)) }
json转换为结构体
1 2 3 4 5 6 func Unmarshal () { b1 := []byte (`{"Name":"tom","Age":20,"Email":"[email protected] "}` ) var m Person json.Unmarshal(b1, &m) fmt.Printf("m: %v\n" , m) }
解析嵌套类型
1 2 3 4 5 6 7 func test3 () { b := []byte (`{"Name":"tom","Age":20,"Email":"[email protected] ", "Parents":["tom", "kite"]}` ) var f interface {} json.Unmarshal(b, &f) fmt.Printf("f: %v\n" , f) }
解析嵌套引用类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func test4 () { type Person struct { Name string Age int Email string Parent []string } p := Person{ Name: "tom" , Age: 20 , Email: "[email protected] " , Parent: []string {"big tom" , "big kite" }, } b, _ := json.Marshal(p) fmt.Printf("b: %v\n" , string (b)) }
io流 Reader Writer 可以扩展到http websocket等场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func test5 () { f, _ := os.Open("a.json" ) dec := json.NewDecoder(f) enc := json.NewEncoder(os.Stdout) for { var v map [string ]interface {} if err := dec.Decode(&v); err != nil { log.Println(err) return } fmt.Printf("v: %v\n" , v) if err := enc.Encode(&v); err != nil { log.Println(err) } } }
也可以读写文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 func test6 () { f, _ := os.Open("a.json" ) defer f.Close() d := json.NewDecoder(f) var v map [string ]interface {} d.Decode(&v) fmt.Printf("v: %v\n" , v) } func test7 () { type Person struct { Name string Age int Email string Parent []string } p := Person{ Name: "tom" , Age: 20 , Email: "[email protected] " , Parent: []string {"big tom" , "big kite" }, } f, _ := os.OpenFile("a.json" , os.O_WRONLY, 0777 ) defer f.Close() e := json.NewEncoder(f) e.Encode(p) }
Golang 标准库encoding/xml xml包实现xml解析
核心的两个函数 1 func Marshal (v interface {}) ([]byte , error)
将struct编码成xml,可以接收任意类型
1 func Unmarshal (data []byte , v interface {}) error
将xml转码成struct结构体
两个核心结构体 1 2 3 type Decoder struct { ... }
从输入流读取并解析xml
1 2 3 type Encoder struct { }
写xml到输出流
实例演示 结构体转换为xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type Person struct { XMLName xml.Name `xml:"person"` Name string `xml:"name"` Age int `xml:"age"` Email string `xml:"email"` } func Marshal () { p := Person{ Name: "tom" , Age: 20 , Email: "[email protected] " , } b, _ := xml.MarshalIndent(p, " " , " " ) fmt.Printf("%v\n" , string (b)) }
也可以读写文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 func read () { b, _ := ioutil.ReadFile("a.xml" ) var p Person xml.Unmarshal(b, &p) fmt.Printf("p: %v\n" , p) } func write () { type Person struct { XMLName xml.Name `xml:"person"` Name string `xml:"name"` Age int `xml:"age"` Email string `xml:"email"` } p := Person{ Name: "tom" , Age: 20 , Email: "[email protected] " , } f, _ := os.OpenFile("a.xml" , os.O_WRONLY, 0777 ) defer f.Close() e := xml.NewEncoder(f) e.Encode(p) }
Golang标准库math 该包包含一些常量和一些有用的数学计算函数,例如:三角函数、随机数、绝对值、平方根等。
常量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fmt.Printf("float64的最大值是:%.f\n" , math.MaxFloat64) fmt.Printf("float64的最小值是:%.f\n" , math.SmallestNonzeroFloat64) fmt.Printf("float32的最大值是:%.f\n" , math.MaxFloat32) fmt.Printf("float32的最小值是:%.f\n" , math.SmallestNonzeroFloat32) fmt.Printf("Int8的最大值是:%d\n" , math.MaxInt8) fmt.Printf("Int8的最小值是:%d\n" , math.MinInt8) fmt.Printf("Uint8的最大值是:%d\n" , math.MaxUint8) fmt.Printf("Int16的最大值是:%d\n" , math.MaxInt16) fmt.Printf("Int16的最小值是:%d\n" , math.MinInt16) fmt.Printf("Uint16的最大值是:%d\n" , math.MaxUint16) fmt.Printf("Int32的最大值是:%d\n" , math.MaxInt32) fmt.Printf("Int32的最小值是:%d\n" , math.MinInt32) fmt.Printf("Uint32的最大值是:%d\n" , math.MaxUint32) fmt.Printf("Int64的最大值是:%d\n" , math.MaxInt64) fmt.Printf("Int64的最小值是:%d\n" , math.MinInt64) fmt.Printf("圆周率默认为:%.200f\n" , math.Pi)
运行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 float64的最大值是:179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368 float64的最小值是:0 float32的最大值是:340282346638528859811704183484516925440 float32的最小值是:0 Int8的最大值是:127 Int8的最小值是:-128 Uint8的最大值是:255 Int16的最大值是:32767 Int16的最小值是:-32768 Uint16的最大值是:65535 Int32的最大值是:2147483647 Int32的最小值是:-2147483648 Uint32的最大值是:4294967295 Int64的最大值是:9223372036854775807 Int64的最小值是:-9223372036854775808 圆周率默认为:3.14159265358979311599796346854418516159057617187500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
常用函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package mainimport ( "fmt" "math" ) func main () { fmt.Printf("[-3.14]的绝对值为:[%.2f]\n" , math.Abs(-3.14 )) fmt.Printf("[2]的16次方为:[%.f]\n" , math.Pow(2 , 16 )) fmt.Printf("10的[3]次方为:[%.f]\n" , math.Pow10(3 )) fmt.Printf("[64]的开平方为:[%.f]\n" , math.Sqrt(64 )) fmt.Printf("[27]的开立方为:[%.f]\n" , math.Cbrt(27 )) fmt.Printf("[3.14]向上取整为:[%.f]\n" , math.Ceil(3.14 )) fmt.Printf("[8.75]向下取整为:[%.f]\n" , math.Floor(8.75 )) fmt.Printf("[10/3]的余数为:[%.f]\n" , math.Mod(10 , 3 )) Integer, Decimal := math.Modf(3.14159265358979 ) fmt.Printf("[3.14159265358979]的整数部分为:[%.f],小数部分为:[%.14f]\n" , Integer, Decimal) }
随机数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package mainimport ( "fmt" "math/rand" "time" ) func init () { rand.Seed(time.Now().UnixNano()) } func main () { for i := 0 ; i < 10 ; i++ { a := rand.Int() fmt.Println(a) } fmt.Println("------------" ) for i := 0 ; i < 10 ; i++ { a := rand.Intn(100 ) fmt.Println(a) } fmt.Println("------------" ) for i := 0 ; i < 10 ; i++ { a := rand.Float32() fmt.Println(a) } }