首页 > golang > Go语言开发(十二)、Go语言常用标准库二
2018
12-21

Go语言开发(十二)、Go语言常用标准库二

Go语言开发(十二)、Go语言常用标准库二

一、os

1、os简介

os 包提供了不依赖平台的操作系统函数接口,设计像Unix风格,但错误处理是go风格,当os包使用时,如果失败后返回错误类型而不是错误数量。

2、os常用接口

func Hostname() (name string, err error) // Hostname返回内核提供的主机名
func Environ() []string // Environ返回表示环境变量的格式为”key=value”的字符串的切片拷贝
func Getenv(key string) string //  Getenv检索并返回名为key的环境变量的值
func Getpid() int // Getpid返回调用者所在进程的进程ID
func Exit(code int) // Exit让当前程序以给出的状态码code退出。一般来说,状态码0表示成功,非0表示出错。程序会立刻终止,defer的函数不会被执行
func Stat(name string) (fi FileInfo, err error) // 获取文件信息
func Getwd() (dir string, err error) // Getwd返回一个对应当前工作目录的根路径
func Mkdir(name string, perm FileMode) error // 使用指定的权限和名称创建一个目录
func MkdirAll(path string, perm FileMode) error // 使用指定的权限和名称创建一个目录,包括任何必要的上级目录,并返回nil,否则返回错误
func Remove(name string) error // 删除name指定的文件或目录
func TempDir() string // 返回一个用于保管临时文件的默认目录
var Args []string // os.Args返回一个字符串数组,其中第一个参数就是执行文件本身

os示例:

package main

import (
   "fmt"
   "os"
)

func main() {
   // 预定义变量, 保存命令行参数
   fmt.Println(os.Args)
   // 获取host name
   fmt.Println(os.Hostname())
   fmt.Println(os.Getpid())
   // 获取全部环境变量
   env := os.Environ()
   for k, v := range env {
      fmt.Println(k, v)
   }
   // 终止程序
   // os.Exit(1)
   // 获取一条环境变量
   fmt.Println(os.Getenv("PATH"))
   // 获取当前目录
   dir, err := os.Getwd()
   fmt.Println(dir, err)
   // 创建目录
   err = os.Mkdir(dir+"/new_file", 0755)
   fmt.Println(err)
   // 创建目录
   err = os.MkdirAll(dir+"/new", 0755)
   fmt.Println(err)
   // 删除目录
   err = os.Remove(dir + "/new_file")
   err = os.Remove(dir + "/new")
   fmt.Println(err)
   // 创建临时目录
   tmp_dir := os.TempDir()
   fmt.Println(tmp_dir)
}

3、File结构体

func Create(name string) (file *File, err error) // Create采用模式0666创建一个名为name的文件,如果文件已存在会截断(为空文件)
func Open(name string) (file *File, err error) // Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据
func (f *File) Stat() (fi FileInfo, err error) // Stat返回描述文件f的FileInfo类型值
func (f *File) Readdir(n int) (fi []FileInfo, err error) //  Readdir读取目录f的内容,返回一个有n个成员的[]FileInfo
func (f *File) Read(b []byte) (n int, err error) // Read方法从f中读取最多len(b)字节数据并写入b
func (f *File) WriteString(s string) (ret int, err error) // 向文件中写入字符串
func (f *File) Sync() (err error) // Sync递交文件的当前内容进行稳定的存储
func (f *File) Close() error // Close关闭文件f,使文件不能用于读写

File示例:

package main

import (
   "fmt"
   "os"
   "time"
)

func main() {
   // 获取当前目录
   dir, err := os.Getwd()
   fmt.Println(dir, err)
   file := dir + "/new"
   var fh *os.File
   fi, _ := os.Stat(file)
   if fi == nil {
      fh, _ = os.Create(file) // 文件不存在就创建
   } else {
      fh, _ = os.OpenFile(file, os.O_RDWR, 0666) // 文件存在就打开
   }
   w := []byte("hello go language" + time.Now().String())
   n, err := fh.Write(w)
   fmt.Println(n, err)
   // 设置下次读写位置
   ret, err := fh.Seek(0, 0)
   fmt.Printf("%s %v %vn","当前文件指针位置", ret, err)
   b := make([]byte, 128)
   n, err = fh.Read(b)
   fmt.Printf("%d %v %sn",n, err, string(b))
   fh.Close()
}

4、FileInfo结构体

FileInfo用来描述一个文件对象。

type FileInfo interface {
   Name() string       // base name of the file
   Size() int64        // length in bytes for regular files; system-dependent for others
   Mode() FileMode     // file mode bits
   ModTime() time.Time // modification time
   IsDir() bool        // abbreviation for Mode().IsDir()
   Sys() interface{}   // underlying data source (can return nil)
}

func Stat(name string) (fi FileInfo, err error)
Stat返回描述文件的FileInfo。如果指定的文件对象是一个符号链接,返回的FileInfo描述该符号链接指向的文件的信息,本函数会尝试跳转该链接
func Lstat(name string) (fi FileInfo, err error)
Lstat返回描述文件对象的FileInfo。如果指定的文件对象是一个符号链接,返回的FileInfo描述该符号链接的信息,本函数不会试图跳转该链接。

package main

import (
   "os"
)

func main() {
   file := "/home/user/hello.go"
   fi, _ := os.Stat(file)
   if fi == nil {
      fh, _ := os.Create(file) // 文件不存在就创建
      fh.Write([]byte("package mainnfunc main(){n}n"))
   } else {
      fh, _ := os.OpenFile(file, os.O_RDWR, 0666) // 文件存在就打开
      fh.Write([]byte("package mainnfunc main(){n}n"))
   }
}

二、bufio

1、bufio简介

bufio模块通过对io模块的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。
在bufio各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据;只有当缓冲区没有数据时,才会从数据源获取数据更新缓冲。

2、Reader

type Reader struct {
   buf          []byte
   rd           io.Reader // reader provided by the client
   r, w         int       // buf read and write positions
   err          error
   lastByte     int
   lastRuneSize int
}

可以通过NewReader函数创建bufio.Reader对象,函数接收一个io.Reader作为参数。因此,bufio.Reader不能直接使用,需要绑定到某个io.Reader上。

func NewReader(rd io.Reader) *Reader
func NewReaderSize(rd io.Reader, size int) *Reader // 可以配置缓冲区的大小

相较于io.Reader,bufio.Reader提供了很多实用的方法,能够更有效的对数据进行读取。bufio.Reader能够对Reader进行细粒度的操作:
A、Read,读取n个byte数据
B、Discard,丢弃接下来n个byte数据
C、Peek,获取当前缓冲区内接下来的n个byte,但不移动指针
D、Reset,清空整个缓冲区

func (b *Reader) Read(p []byte) (n int, err error)
func (b *Reader) Discard(n int) (discarded int, err error)
func (b *Reader) Peek(n int) ([]byte, error)
func (b *Reader) Reset(r io.Reader)

bufio.Reader还提供了多个更高抽象层次的方法对数据进行简单的结构化读取,如下:
A、ReadByte,读取一个byte
B、ReadRune,读取一个utf-8字符
C、ReadLine,读取一行数据,由’n’分隔
D、ReadBytes,读取一个byte列表
E、ReadString,读取一个字符串

func (b *Reader) ReadByte() (byte, error)
func (b *Reader) ReadRune() (r rune, size int, err error)
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
func (b *Reader) ReadBytes(delim byte) ([]byte, error)
func (b *Reader) ReadString(delim byte) (string, error)

bufio.Reader使用示例:

package main

import (
   "strings"
   "fmt"
   "bufio"
)

func main() {
   r := strings.NewReader("hello world !")
   reader := bufio.NewReader(r)

   bytes, _ := reader.Peek(5)
   fmt.Printf("%sn",bytes)
   n, _ := reader.Read(bytes)
   fmt.Println(n)
   reader.Discard(1)

   for {
      str, err := reader.ReadString(byte(' '))
      fmt.Println(str)
      if err != nil {
         return
      }
   }
}
// output
// hello
// 5
// world
// !

3、Writer

type Writer struct {
   err error
   buf []byte
   n   int
   wr  io.Writer
}
func NewWriter(w io.Writer) *Writer
func NewWriterSize(w io.Writer, size int) *Writer

创建Writer对象的接口

func (b *Writer) Write(p []byte) (nn int, err error) // 写入n byte数据
func (b *Writer) Reset(w io.Writer) // 重置当前缓冲区
func (b *Writer) Flush() error // 清空当前缓冲区,将数据写入输出
func (b *Writer) WriteByte(c byte) error  // 写入一个字节
func (b *Writer) WriteRune(r rune) (size int, err error) // 写入一个字符
func (b *Writer) WriteString(s string) (int, error) // 写入一个字符串
func (b *Writer) Available() int // 缓存中有多少字节空间可用
func (b *Writer) Buffered() int // 当前缓存已经写入了多少字节
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) // 实现io.ReaderFrom

4、ReadWriter

type ReadWriter struct {
   *Reader
   *Writer
}

ReadWriter实现了io.ReadWriter。
func NewReadWriter(r *Reader, w *Writer) *ReadWriter
ReadWriter对象创建

5、Scanner

type Scanner struct {
   r            io.Reader // The reader provided by the client.
   split        SplitFunc // The function to split the tokens.
   maxTokenSize int       // Maximum size of a token; modified by tests.
   token        []byte    // Last token returned by split.
   buf          []byte    // Buffer used as argument to split.
   start        int       // First non-processed byte in buf.
   end          int       // End of data in buf.
   err          error     // Sticky error.
   empties      int       // Count of successive empty tokens.
   scanCalled   bool      // Scan has been called; buffer is in use.
   done         bool      // Scan has finished.
}

工程开发中推荐使用Scanner对数据进行读取,而非直接使用Reader类。Scanner可以通过splitFunc将输入数据拆分为多个token,然后依次进行读取。
func NewScanner(r io.Reader) *Scanner
创建scanner对象
func (s *Scanner) Split(split SplitFunc)
设置scanner的分割函数。
在使用scanner前还需要设置splitFunc(默认为ScanLines),splitFunc用于将输入数据拆分为多个token。bufio模块提供了几个默认splitFunc,能够满足大部分场景的需求,包括:
A、ScanBytes,按照byte进行拆分
B、ScanLines,按照行(“n”)进行拆分
C、ScanRunes,按照utf-8字符进行拆分
D、ScanWords,按照单词(” “)进行拆分
通过Scanner的Split方法,可以为Scanner指定splitFunc。使用方法如下:

scanner := bufio.NewScanner(os.StdIn)
scanner.split(bufio.ScanWords)

设置分割方式
type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
函数接收两个参数,第一个参数是输入数据,第二个参数是一个标识位,用于标识当前数据是否为结束。函数返回三个参数,第一个是本次split操作的指针偏移;第二个是当前读取到的token;第三个是返回的错误信息。

func (s *Scanner) Scan() bool
func (s *Scanner) Text() string
func (s *Scanner) Bytes() []byte

在完成Scanner初始化后,通过Scan方法可以在输入中向前读取一个token,读取成功返回True;使用Text和Bytes方法获取token,Text返回一个字符串,Bytes返回字节数组。
Scanner使用示例:

package main

import (
   "strings"
   "fmt"
   "bufio"
)

func main() {
   scanner := bufio.NewScanner(strings.NewReader("hello world !"))
   scanner.Split(bufio.ScanWords)
   for scanner.Scan() {
      fmt.Println(scanner.Text())
   }
}
// output
// hello
// world
// !

三、ioutil

1、ioutil简介

ioutil提供了对io包的封装函数。

2、ReadAll

func ReadAll(r io.Reader) ([]byte, error)
ReadAll读取r中的所有数据
返回读取的数据和读取过程中遇到的任何错误。如果读取成功,则err返回nil,而不是EOF。

s := strings.NewReader("Hello World!")
ra, _ := ioutil.ReadAll(s)
fmt.Printf("%s", ra)
// Hello World!

func ReadFile(filename string) ([]byte, error)
ReadFile读取文件中的所有数据,返回读取的数据和读取过程中遇到的任何错误。如果读取成功,则err返回nil,而不是EOF。

content, err := ioutil.ReadFile("/home/user/hello.txt")
if err != nil {
   log.Fatal(err)
}

fmt.Printf("File contents: %s", content)

3、WriteFile

func WriteFile(filename string, data []byte, perm os.FileMode) error
WriteFile向文件filename中写入数据data,如果文件不存在,则以perm权限创建该文件;如果文件存在,则先清空文件,然后再写入。返回写入过程中遇到的任何错误。

filename := "/home/user/hello.txt"
data := []byte("Hello World!")
ioutil.WriteFile(filename, data, os.ModeAppend)
contents, _ := ioutil.ReadFile(filename)
fmt.Printf("%s", contents)
// Hello World!

4、ReadDir

func ReadDir(dirname string) ([]os.FileInfo, error)
ReadDir读取目录dirmane中的所有目录和文件(不包括子目录)
返回读取到的文件的信息列表和读取过程中遇到的任何错误,返回的文件列表是经过排序的。

rd, err := ioutil.ReadDir("/home/user")
for _, fi := range rd {
   fmt.Println("")
   fmt.Println(fi.Name())
   fmt.Println(fi.IsDir())
   fmt.Println(fi.Size())
   fmt.Println(fi.ModTime())
   fmt.Println(fi.Mode())
}
fmt.Println("")
fmt.Println(err)

5、TempDir

func TempDir(dir, prefix string) (name string, err error)
TempDir功能同TempFile,只不过创建的是目录,返回值也只返目录的完整路径。

content := []byte("temporary file's content")
dir, err := ioutil.TempDir("/home/user", "example")
if err != nil {
   log.Fatal(err)
}

defer os.RemoveAll(dir) // clean up

tmpfn := filepath.Join(dir, "tmpfile")
if err := ioutil.WriteFile(tmpfn, content, 0666); err != nil {
   log.Fatal(err)
}

6、TempFile

func TempFile(dir, prefix string) (f *os.File, err error)
TempFile在目录dir中创建一个临时文件并将其打开,文件名以prefix为前缀
返回创建的文件的对象和创建过程中遇到的任何错误
如果dir为空,则在系统的临时目录中创建临时文件
如果环境变量中没有设置系统临时目录,则在/tmp中创建临时文件
调用者可以通过f.Name()方法获取临时文件的完整路径
调用TempFile所创建的临时文件,应该由调用者自己移除

content := []byte("temporary file's content")
tmpfile, err := ioutil.TempFile("/home/user", "example")
if err != nil {
   log.Fatal(err)
}

defer os.Remove(tmpfile.Name()) // clean up

if _, err := tmpfile.Write(content); err != nil {
   log.Fatal(err)
}
if err := tmpfile.Close(); err != nil {
   log.Fatal(err)
}

7、Discard

var Discard io.Writer = devNull(0)
Discard是一个io.Writer,对它进行的任何Write调用都将无条件成功。devNull优化的实现ReadFrom,因此io.Copy到ioutil.Discard避免不必要的工作,因此其一定会成功。但是ioutil.Discard不记录copy得到的数值。

a := strings.NewReader("hello")
p := make([]byte, 20)
io.Copy(ioutil.Discard, a)
ioutil.Discard.Write(p)
fmt.Println(p)
//[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

8、NopCloser

func NopCloser(r io.Reader) io.ReadCloser
ReadCloser接口组合了基本的Read和Close方法。NopCloser将提供的 Reader r用空操作Close方法包装后作为ReadCloser返回。

s := strings.NewReader("hello world!")
r := ioutil.NopCloser(s)
r.Close()
p := make([]byte, 10)
r.Read(p)
fmt.Println(string(p))
//hello worl

四、bytes

1、bytes简介

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

2、基本函数

func Contains(b,subslice []bytes) bool
检查字节切片b是否包含子切片subslice,如果包含返回true,否则返回false。
func Count(s,sep []byte) int
计算字节切片sep在字节切片s中非重叠显示的个数。
func Repeat(b[]byte,count int) []byte
把切片b复制count个,然后合成一个新的字节切片返回。
func Replace(s,old,new []byte,n int) []byte
返回字节切片s的一个副本,并把前n个不重叠的子切片old替换为new;如果n小于0,则不限制替换的数量。参数n为替换的次数。

func Runes(s []byte) []rune
把s转换为UTF-8编码的字节序列,并返回对应的Unicode切片
func Join(s [][]byte,sep[]byte) []byte
用字节切片sep把s中的每个字节切片连成一个字节切片并返回。
基本函数示例:

package main

import (
   "fmt"
   "bytes"
)

func main() {
   //Contains
   b := []byte("hello") //字符串强转为byte切片
   sublice1 := []byte("h")
   sublice2 := []byte("l")
   fmt.Println(bytes.Contains(b,sublice1))// true
   fmt.Println(bytes.Contains(b,sublice2))// false

   //Count
   s := []byte("hello world")
   sep1 := []byte("ll")
   sep2 := []byte("l")
   sep3 := []byte("o")
   fmt.Println(bytes.Count(s,sep1))// 1
   fmt.Println(bytes.Count(s,sep2))// 3
   fmt.Println(bytes.Count(s,sep3))// 2

   //Repeat
   b = []byte("hello world")
   fmt.Println(string(bytes.Repeat(b,1)))// hello world
   fmt.Println(string(bytes.Repeat(b,2)))// hello worldhello world

   //Replace
   s = []byte("hello,world")
   old := []byte("o")
   news := []byte("ee")
   fmt.Println(string(bytes.Replace(s,old,news,0)))//hello,world
   fmt.Println(string(bytes.Replace(s,old,news,1)))//hellee,world
   fmt.Println(string(bytes.Replace(s,old,news,2)))//hellee,weerld
   fmt.Println(string(bytes.Replace(s,old,news,-1)))//hellee,weerld

   //Runes
   s = []byte("你好世界")
   r := bytes.Runes(s)
   fmt.Println("转换前字符串的长度: ",len(s))//12
   fmt.Println("转换后字符串的长度: ",len(r))//4

   //Join
   ss := [][]byte{[]byte("你好"),[]byte("世界")}
   sep4 := []byte(",")
   fmt.Println(string(bytes.Join(ss,sep4)))//你好,世界
   sep5 := []byte("#")
   fmt.Println(string(bytes.Join(ss,sep5)))//你好#世界
}

3、比较函数

func Compare(a,b[]byte) int
根据字节的值比较字节切片a和b的大小,如果a=b,返回0,如果a>b返回1,如果a小于b返回-1。
func Equal(a,b[]byte) bool
比较2个字节切片是否相等,如果参数为nil,则等同于空的字节切片,如果a=b,则返回true,否则返回false.区分大小写。
func EqualFold(s,t[]byte) bool
把s和t转换成UTF-8字符串进行比较,并且忽略大小写,如果s=t,返回true,否则,返回false。
比较函数示例:

package main

import (
   "fmt"
   "bytes"
)

func main() {
   //Compare
   a := []byte("hello,go")
   b := []byte("hello,world")
   fmt.Println(bytes.Compare(a,b))//-1
   b =[]byte("hello,c")
   fmt.Println(bytes.Compare(a,b))//1
   b =[]byte("hello,World")
   fmt.Println(bytes.Compare(a,b))//1  小写字母大于大写字母
   b =[]byte("b")
   fmt.Println(bytes.Compare(a,b))//-1 从第一个字节开始比较,如果相同再比较长度

   //Equal
   a = []byte("abc")
   b = []byte("ABC")
   fmt.Println(bytes.Equal(a,b))//false
   fmt.Println(bytes.Equal(a,nil))//false
   b = []byte("abc")
   fmt.Println(bytes.Equal(a,b))//true

   //EqualFold
   a = []byte("abc")
   b = []byte("ABC")
   fmt.Println(bytes.EqualFold(a,b))//true
}

4、前后缀检查

func HasPrefix(s,prefix[]byte) bool
检查字节切片s的前缀是否为prefix,如果是返回true,如果不是返回false
func HashSuffix(s,suffix[]byte) bool
检查字节切片s的后缀是否为suffix,如果是返回true,否则返回false。
前后缀检查示例:

package main

import (
   "fmt"
   "bytes"
)

func main() {
   //HasPrefix
   s := []byte("test_Hello.txt")
   prefix := []byte("test")
   fmt.Println(bytes.HasPrefix(s,prefix))//true
   prefix = []byte("Test")
   fmt.Println(bytes.HasPrefix(s,prefix))//false

   //HashSuffix
   suffix := []byte("txt")
   fmt.Println(bytes.HasSuffix(s,suffix))//true
}

5、位置索引

字节切片位置索引函数共有8个,Index()、IndexAny()、IndexByte()、IndexFunc()、IndexRune()、LastIndex()、LastIndexAny()和LastIndexFunc()。
func Index(s,sep []byte) int
返回sep在s中第一次出现的位置索引(从0开始),如果sep中不在s中则返回-1
func IndexAny(s []byte,chars string) int
把s解析为UTF-8编码的字节序列,返回chars中任何一个字符在s中第一次出现的索引位置;如果s中不包含chars中任何一个字符,则返回-1
func IndexByte(s[]byte,c byte) int
检查字节c在s中第一次出现的位置索引;如果s中不包含c则返回-1
func IndexFunc(s[]byte,f func(r rune)bool) int
把s解析为UTF-8字节序列,并返回一个满足f(c)=true的字符c的位置索引,如果没有满足则返回-1
func IndexRune(s[]byte,r rune) int
把s解析为UTF-8字节序列,并返回rune类型的字符r在s中的位置索引,如果s中不包含r则返回-1
func LastIndex(s,sep[]byte) int
返回sep在s中最后一次出现的位置索引,如果s中不包含sep,则返回-1
func LastIndexAny(s[]byte,chars string) int
把s解析为UTF-8字节序列,返回chars中任何一个字符在s中最后
出现的位置索引,如果chars为空或者s中不包含chars中的任意字符,则返回-1
func LastIndexFunc(s[]byte,f func(r rune)bool) int
把s解析成UTF-8字节序列,返回满足f(s)=true的字符c在s中最后
一次出现的位置索引,如果没有找到则返回-1
位置索引示例:

package main

import (
   "fmt"
   "bytes"
)

func main() {
   //Index
   a := []byte("hello,world")
   fmt.Println(bytes.Index(a,[]byte("o")))//4
   fmt.Println(bytes.Index(a,[]byte("ll")))//2
   fmt.Println(bytes.Index(a,[]byte("w")))//6

   //IndexAny
   fmt.Println(bytes.IndexAny(a,"h"))//0
   fmt.Println(bytes.IndexAny(a,"l"))//2

   //IndexByte
   s := []byte("hello,world")
   var ch byte = 'w'
   fmt.Println(bytes.IndexByte(s,ch))//6

   //IndexFunc,可以接收匿名函数
   fmt.Println(bytes.IndexFunc(s,func (a rune)bool{
      if a == 'o'{
         return true
      }else{
         return false
      }
   }))//4

   //IndexRune
   fmt.Println(bytes.IndexRune(s,'e'))//1
   fmt.Println(bytes.IndexRune(s,'a'))//-1

   //LastIndex
   fmt.Println(bytes.LastIndex(s,[]byte("g")))//-1
   fmt.Println(bytes.LastIndex(s,[]byte("e")))//1
   fmt.Println(bytes.LastIndex(s,[]byte("o")))//7

   //LastIndexAny
   fmt.Println(bytes.LastIndexAny(s,"world"))//10
   fmt.Println(bytes.LastIndexAny(s,"l"))//9
   fmt.Println(bytes.LastIndexAny(s,"d"))//10

   //LastIndexFunc
   fmt.Println(bytes.LastIndexFunc(s,func(r rune)bool{
      if r=='d'{
         return true
      }else {
         return false
      }
   }))//10
}

6、分割函数

字节切片分割函数共有6个,Fields(),FieldsFunc(),Split(),SplitN(), 
SplitAfter()和SplitAfterN()。
func Fields(s[]byte) [][]byte
把字节切片s按照一个或者连续多个空白字符分割成多个字节切片,如果s只包含空白字符则返回空字节切片,其中参数s准备分割的字节切片
func FieldsFunc(s []byte,f func(r rune)bool) [][]byte
把s解析为UTF-8字节序列,对于每个Unicode字符c,如果f(c)返回true就把c作为分割字符对s进行拆分。如果所有字符都满足f(c)为true,则返回空切片
func Split(s,sep[]byte)[][]byte
把s用sep分割成多个字节切片并返回,如果sep为空,Split则把s切分成每个字节切片对应一个UTF-8字符,Split()等效于参数为n的splitN()函数。
func SplitAfter(s,sep[]byte)[][]byte
使用sep作为后缀把s切分成多个字节切片并返回。如果sep为空,则把s切分成每个字节切片对应一个UTF-8字符。
func SplitAfterN(s,sep[]byte,n int)[][]byte
用sep作为后缀把s切分成多个字节切片并返回。如果sep为空,则把s切分成每个字节切片对应一个UTF-8字符。参数n决定返回切片的长度:如果n>0,最多返回n个子字节切片,子切片可能包含未切分的字节序列;如果n=0,返回空切片;如果n< 0,返回所有子切片。
func SplitN(s,sep []byte,n int)[][]byte
把s用sep分割成多个字节切片并返回,如果sep为空,Split则把s切分成每个字节切片对应一个UTF-8字符,参数n决定返回长度,n>0最多返回n个子切片;n==0返回返回空切片,n小于0返回所有子切片。
分割函数示例:

package main

import (
   "fmt"
   "bytes"
)

func main() {
   //Fields ,返回的是2维切片
   s := []byte("hello world")
   for _,v := range bytes.Fields(s){
      //遍历获取1维切片,再强转为字符串
      fmt.Print(string(v)+",") // hello,world,
   }
   fmt.Println()
   //FieldsFunc,返回是2维切片,接收匿名函数
   s = []byte("hello,world")
   for _,v := range bytes.FieldsFunc(s,func(r rune)bool{
      if r == ','{
         return true //按照空白字符分割
      }else{
         return false
      }
   }){
      fmt.Print(string(v)+",")// hello,world,
   }
   fmt.Println()
   //Split
   s = []byte("天山老妖")
   for _,v := range bytes.Split(s,[]byte("山")){
      fmt.Print(string(v)+",")//天,老妖,
   }
   fmt.Println()
   for _,v := range bytes.Split(s,nil){
      fmt.Print(string(v)+",")//天,山,老,妖,
   }
   fmt.Println()
   //SplitAfter
   for _,v := range bytes.SplitAfter(s,[]byte("山")){
      fmt.Print(string(v)+",")//天山,老妖,
   }
   fmt.Println()
   for _,v := range bytes.SplitAfter(s,nil){
      fmt.Print(string(v)+",")//天,山,老,妖,
   }
   fmt.Println()
   //SplitAfterN
   s = []byte("hello,world,hello,go")
   for _,v := range bytes.SplitAfterN(s,[]byte(","),0){
      fmt.Print(string(v)+",") //什么都不输出
   }
   fmt.Println()
   for _,v := range bytes.SplitAfterN(s,[]byte(","),4){
      fmt.Print(string(v))//hello,world,hello,go
   }
   fmt.Println()
   for _,v := range bytes.SplitAfterN(s,[]byte(""),-1){
      fmt.Print(string(v))//hello,world,hello,go
   }
   fmt.Println()
   //SplitN
   s = []byte("hello,world")
   for _,v := range bytes.SplitN(s,[]byte("he"),0){
      fmt.Print(string(v)+",") //
   }
   fmt.Println()
   for _,v := range bytes.SplitN(s,[]byte("o"),3){
      fmt.Print(string(v) + ",")//hell,,w,rld,
   }
   fmt.Println()
   for _,v := range bytes.SplitN(s,[]byte("ll"),-1){
      fmt.Print(string(v)+",")//he,o,world,
   }
}

7、大小写处理函数

共有7个函数,Title(),ToTitle(),ToTitleSpecial(),ToLower(),ToLowerSpecial(),ToUpper() 和ToUpperSpecial()。
func Title(s[]byte) []byte
返回一个s的副本,把s中每个单词的首字母改成Unicode字符大写
func ToTitle(s []byte) []byte
返回s的一个副本,并把其中所有Unicode字符转为大写
func ToTitleSpecial(_case unicode.SpecialCase,s []byte) []byte
返回s的一个副本,并把其中所有Unicode字符根据_case指定的规则转成大写
func ToLower(s []byte)[]byte
返回s的一个副本,并把其中的所有Unicode字符转为小写
func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte
返回s的一个副本,并把其中所有Unicode字符根据_case定的规则转换成小写
func ToUpper(s []byte) []byte
返回s的一个副本,并把其中所有Unicode字符都转为大写
func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte
返回s的一个副本,并把其中所有Unicode字符都根据_case指定的规则转成大写
大小写处理函数示例:

package main

import (
   "fmt"
   "bytes"
   "unicode"
)

func main() {
   s := []byte("hello,go")
   fmt.Println(string(bytes.Title(s)))// Hello,Go
   fmt.Println(string(bytes.ToTitle(s)))// HELLO,GO
   fmt.Println(string(bytes.ToTitleSpecial(unicode.AzeriCase,s)))// HELLO,GO
   s = []byte("Hello,Go")
   fmt.Println(string(bytes.ToLower(s)))// hello,go
   fmt.Println(string(bytes.ToLowerSpecial(unicode.AzeriCase,s)))// hello,go
   s = []byte("Hello,Go")
   fmt.Println(string(bytes.ToUpper(s)))// HELLO,GO
   fmt.Println(string(bytes.ToUpperSpecial(unicode.AzeriCase,s)))// HELLO,GO
}

8、子字节切片处理函数

子字节切片处理函数共有9个,Trim(),TrimFunc(),TrimLeft(),TrimLeftFunc(),TrimRight(),TrimRightFunc(),TrimSpace(),TrimPrefix()和TrimSuffix()。
func Trim(s []byte, cutset string) []byte
返回s的子字节切片,cutset中任意出现在s的首部和尾部的连续字符将被删除。
func TrimFunc(s []byte, f func(r rune) bool) []byte
返回s的子字节切片,删除s首部和尾部连接的满足f(c)=true的字符c。
func TrimLeft(s []byte, cutset string) []byte
返回s的子字节切片,cutset中任意出现在s首部的连续字符被删除。
func TrimLeftFunc(s []byte, f func(r rune) bool) []byte
返回s的一个子字节切片、删除s首部连续满足f(c)=true的字符c。
func TrimRight(s []byte, cutset string) []byte
返回s的子字节切片,cutset中任意出现在s尾部的连续字符被删除。
func TrimRightFunc(s []byte, f func(r rune) bool) []byte
返回s的一个子字节切片、删除s尾部连续满足f(c)=true的字符c
func TrimSpace(s []byte) []byte
返回s的一个子字节切片,并删除s中开始和结尾处的连续的Unicode空白字符。
func TrimPrefix(s, prefix []byte) []byte
返回s的一个子字节切片,并删除前缀为prefix的部分
func TrimSuffix(s, suffix []byte) []byte
返回s的一个子字节切片,并删除后缀为suffix的部分
子字节切片处理函数示例:

package main

import (
   "fmt"
   "bytes"
)

func main() {
   //Trim
   s := []byte(" Hello,Go  ")
   fmt.Println(string(bytes.Trim(s," ")))// Hello,Go

   //TrimFunc
   s = []byte("hello world")
   fmt.Println(string(bytes.TrimFunc(s,func(r rune)bool{
      if r=='h' || r=='d'{
         return true
      }else{
         return false
      }
   }))) //ello worl

   s = []byte("hello,worldo")
   fmt.Println(string(bytes.TrimFunc(s,func(r rune)bool{
      if r=='h' || r=='o'{
         return true
      }else{
         return false
      }
   }))) // ello,world

   s = []byte("hello,world")
   fmt.Println(string(bytes.TrimFunc(s,func(r rune)bool{
      if r=='h' && r=='o'{
         return true
      }else{
         return false
      }
   }))) // hello,world

   //TrimLeft
   fmt.Println(string(bytes.TrimLeft(s,"h")))// ello,world
   fmt.Println(string(bytes.TrimLeft(s,"l")))// hello,world

   //TrimLeftFunc
   fmt.Println(string(bytes.TrimLeftFunc(s,func(r rune)bool{
      if r == 'h' || r=='l'{
         return true
      }else{
         return false
      }

   }))) // ello,world

   //TrimRight
   fmt.Println(string(bytes.TrimRight(s,"d")))// hello,worl

   //TrimRightFunc
   fmt.Println(string(bytes.TrimRightFunc(s,func(r rune)bool{
      if r == 'd'{
         return true
      }else{
         return false
      }

   })))// hello,worl

   //TrimSpace
   s = []byte("  hello world   ")
   fmt.Println(string(bytes.TrimSpace(s)))// hello world

   //TrimPrefix
   s = []byte("test_Go")
   fmt.Println(string(bytes.TrimPrefix(s,[]byte("test_"))))// Go
   fmt.Println(string(bytes.TrimPrefix(s,[]byte("Test"))))// test_Go

   //TrimSuffix
   s = []byte("hello.go")
   fmt.Println(string(bytes.TrimSuffix(s,[]byte(".go"))))// hello
   fmt.Println(string(bytes.TrimSuffix(s,[]byte(".cpp"))))// hello.go
}

五、path

1、path简介

path实现了对斜杠分隔的路径进行操作的函数。
filepath包实现了兼容各操作系统的文件路径操作函数

2、path常用接口

func IsAbs(path string) bool
判断是否是一个绝对路径
func Split(path string) (dir, file string)
将路径分割为路径和文件名
func Join(elem ...string) string
将多个字符串合并为一个路径
func Ext(path string) string
返回路径中扩展部分
func Base(path string) string
返回路径的最后一个元素
func Dir(path string) string
返回路径中目录部分
func Clean(path string) string
返回同目录的最短路径
func Match(pattern, name string) (matched bool, err error)
正则是否匹配路径(shell文件名匹配)

package main

import (
   "fmt"
   "path"
)

func main() {
   pt := "~/GoLang"

   // 判断是否是一个绝对路径
   is_abs := path.IsAbs(pt)
   fmt.Println(is_abs) // false

   // 将路径分割为路径和文件名
   pf := "/home/user/hello.go"
   dir, file := path.Split(pf)
   fmt.Println(dir, file) // /home/user/ hello.go

   // 将多个字符串合并为一个路径
   dir_join := path.Join("usr", "local", "bin")
   fmt.Println(dir_join) // usr/local/bin

   // 返回路径中扩展
   file_ext := path.Ext(pf)
   fmt.Println(file_ext) // .go

   // 返回路径的最后一个元素
   dir_base := path.Base(pf)
   fmt.Println(dir_base) // hello.go

   // 返回路径中目录部分
   dir = path.Dir(pf)
   fmt.Println(dir) // /home/user

   // 返回同目录的最短路径
   dir_a := "/usr/../opt/../home/user"
   fmt.Println(path.Clean(dir_a)) // /home/user

   // 正则是否匹配路径
   is_match, err := path.Match("*.xml", "a.xml")
   fmt.Println(is_match, err) // true <nil>
}

3、filepath常用接口

filepath.Separator
预定义变量,表示路径分隔符 /
filepath.ListSeparator
预定义变量,表示环境变量分隔符 :
func Abs(path string) (string, error)
返回path相对当前路径的绝对路径
func Clean(path string) string
返path的最短路径
func Rel(basepath, targpath string) (string, error)
返回targpath相对 basepath路径
func EvalSymlinks(path string) (string, error)
返回软链指向的路径
func VolumeName(path string) string
返回路径最前面的卷名
func ToSlash(path string) string
路径分隔符替换为 /
func FromSlash(path string) string
/ 替换为路径分隔符
func SplitList(path string) []string
分隔环境变量里面的路径
func Walk(root string, walkFn WalkFunc) error
遍历root目录下的文件树,并调用walkFn

package main

import (
   "fmt"
   "os"
   "path/filepath"
)

// 打印路径名称
func pathName(path string, info os.FileInfo, err error) error {
   if err != nil {
      return err
   } else {
      fmt.Println(path)
   }
   return nil
}

func main() {
   // 预定义变量
   fmt.Println(string(filepath.Separator), string(filepath.ListSeparator))

   // 返回path 相对当前路径的绝对路径
   dir := "/home/user/hello.go"
   real_dir, err := filepath.Abs(dir)
   fmt.Println(real_dir, err)

   // 返回path 的最短路径
   dir = "/usr/../etc/../tmp"
   clear_dir := filepath.Clean(dir)
   fmt.Println(clear_dir) // /tmp

   // 返回targpath 相对 basepath路径
   basepath, targpath := "/usr/local", "/usr/local/go/bin"
   rel_dir, err := filepath.Rel(basepath, targpath)
   fmt.Println(rel_dir, err) // go/bin <nil>

   // 返回软链指向的路径
   symlink := "/usr/local"
   real_dir, err = filepath.EvalSymlinks(symlink)
   fmt.Println(real_dir, err) // /usr/local <nil>

   // 返回路径最前面的卷名
   root := "/usr/local/go"
   vol := filepath.VolumeName(root)
   fmt.Println(vol) // ''

   // 路径分隔符替换为 `/`
   slash_dir := filepath.ToSlash(root)
   fmt.Println(slash_dir) // /usr/local/go

   //  `/` 替换为路径分隔符
   from_slash := filepath.FromSlash(slash_dir)
   fmt.Println(from_slash) // /usr/local/go

   // 分隔环境变量里面的路径
   env_path := "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/go/bin"
   env_slice := filepath.SplitList(env_path)
   for k, v := range env_slice {
      fmt.Println(k, v)
   }
   // 0 /usr/local/bin
   // 1 /usr/bin
   // 2 /bin
   // 3 /usr/sbin
   // 4 /sbin
   // 5 /opt/X11/bin
   // 6 /usr/local/go/bin

   // 遍历 root 目录下的文件树,并调用 walkFn
   root_dir, err := os.Getwd()
   err = filepath.Walk(root_dir, pathName)
   fmt.Println(err)
}

4、目录遍历

Walk(root stirng, walkFn WalkFunc) error
// 参数root可以是文件名也可以是目录名;walkFn是自定义的函数

func Walk(root string, walkFn WalkFunc) error {

   //获取root的描述信息
   info, err := os.Lstat(root)
   if err != nil {
      //如果获取描述信息发生错误,返回err由定义的walkFn函数处理
      err = walkFn(root, nil, err)
   } else {
      //调用walk(root, info, walkFn)函数进行递归遍历root
      err = walk(root, info, walkFn)
   }
   if err == SkipDir {
      return nil
   }
   return err
}

Walk方法会遍历root下的所有文件(包含root)并对每一个目录和文件都调用walkFunc方法。在访问文件和目录时发生的错误都会通过error参数传递给WalkFunc方法。文件是按照词法顺序进行遍历的,通常让输出更漂亮,但也会导致处理非常大的目录时效率会降低。另外,Walk函数不会遍历符号链接。
type WalkFunc func(path string, info os.FileInfo, err error) 
WalkFunc是一个方法类型,Walk函数在遍历文件或者目录时调用。调用时将参数传递给path,将Walk函数中的root作为前缀。将root + 文件名或者目录名作为path传递给WalkFunc函数。例如在"dir"目录下遍历到"a"文件,则path="dir/a";Info是path所指向文件的文件信息。如果在遍历过程中出现了问题,传入参数err会描述这个问题。WalkFunc函数可以处理这个问题,Walk将不会再深入该目录。如果函数会返回一个错误,Walk函数会终止执行;只有一个例外,我们也通常用这个来跳过某些目录。当WalkFunc的返回值是filepaht.SkipDir时,Walk将会跳过这个目录,照常执行下一个文件。

func walk(path string, info os.FileInfo, walkFn WalkFunc) error {

   //调用定义的walkFn自定义函数处理
   err := walkFn(path, info, nil)
   if err != nil {
      //返回错误,且该目录可以跳过
      if info.IsDir() && err == SkipDir {
         return nil
      }
      return err
   }

   //如果是文件,则遍历下一个
   if !info.IsDir() {
      return nil
   }

   //读取该path下的所有目录和文件
   names, err := readDirNames(path)
   if err != nil {
      //发生错误,调用自定义函数处理
      return walkFn(path, info, err)
   }

   //遍历文件和目录列表
   for _, name := range names {
      //路径path/name
      filename := Join(path, name)
      //获取该文件或者目录信息
      fileInfo, err := lstat(filename)
      if err != nil {
         //发生错误,调用自定义函数处理
         if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir {
            return err
         }
      } else {
         //这里递归调用,获取root下各级文件和目录信息,在自定义函数walkFn里做处理
         err = walk(filename, fileInfo, walkFn)
         if err != nil {
            //遍历文件发生错误或者目录发生错误且不能跳过,则返回err
            if !fileInfo.IsDir() || err != SkipDir {
               return err
            }
         }
      }
   }
   return nil
}
作者:golang中国
golang中国

本文》有 8832 条评论

留下一个回复