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 %v\n","當前檔案指標位置", ret, err) b := make([]byte, 128) n, err = fh.Read(b) fmt.Printf("%d %v %s\n",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 main\nfunc main(){\n}\n")) } else { fh, _ := os.OpenFile(file, os.O_RDWR, 0666) // 檔案存在就開啟 fh.Write([]byte("package main\nfunc main(){\n}\n")) } }
二、bufio
1、bufio簡介
bufio模組通過對io模組的封裝,提供了資料緩衝功能,能夠一定程度減少大塊資料讀寫帶來的開銷。
在bufio各個元件內部都維護了一個緩衝區,資料讀寫操作都直接通過快取區進行。當發起一次讀寫操作時,會首先嚐試從緩衝區獲取資料;只有當緩衝區沒有資料時,才會從資料來源獲取資料更新緩衝。
2、Reader
type Reader struct { buf[]byte rdio.Reader // reader provided by the client r, wint// buf read and write positions errerror lastByteint 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("%s\n",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 nint wrio.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 { rio.Reader // The reader provided by the client. splitSplitFunc // 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. startint// First non-processed byte in buf. endint// End of data in buf. errerror// Sticky error. emptiesint// Count of successive empty tokens. scanCalledbool// Scan has been called; buffer is in use. donebool// 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 }