go语言入门(9)文本文件处理
1,字符串处理
字符串在开发中经常用到,包括用户的输入,数据库读取的数据等,我们经常需要对字符串进行分割、连接、转换等操作,我们可以通过Go标准库中的strings和strconv两个包中的函数进行相应的操作。
1.1字符串操作
下面这些函数来自于strings包,这里介绍一些我平常经常用到的函数,更详细的请参考官方的文档。
1) Contains
func Contains(s, substr string) bool 功能:字符串s中是否包含substr,返回bool值
示例代码:
fmt.Println(strings.Contains("seafood", "foo")) fmt.Println(strings.Contains("seafood", "bar")) fmt.Println(strings.Contains("seafood", "")) fmt.Println(strings.Contains("", "")) //运行结果: //true //false //true //true
2)Join
func Join(a []string, sep string) string 功能:字符串链接,把slice a通过sep链接起来
示例代码:
s := []string{"foo", "bar", "baz"} fmt.Println(strings.Join(s, ", ")) //运行结果:foo, bar, baz
3)Index
func Index(s, sep string) int 功能:在字符串s中查找sep所在的位置,返回位置值,找不到返回-1
示例代码:
fmt.Println(strings.Index("chicken", "ken")) fmt.Println(strings.Index("chicken", "dmr")) //运行结果: // 4 // -1
4)Repeat
func Repeat(s string, count int) string 功能:重复s字符串count次,最后返回重复的字符串
示例代码:
fmt.Println("ba" + strings.Repeat("na", 2)) //运行结果:banana
5)Replace
func Replace(s, old, new string, n int) string 功能:在s字符串中,把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换
示例代码:
fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2)) fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1)) //运行结果: //oinky oinky oink //moo moo moo
6)Split
func Split(s, sep string) []string 功能:把s字符串按照sep分割,返回slice
fmt.Printf("%q\n", strings.Split("a,b,c", ",")) fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a ")) fmt.Printf("%q\n", strings.Split(" xyz ", "")) fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins")) //运行结果: //["a" "b" "c"] //["" "man " "plan " "canal panama"] //[" " "x" "y" "z" " "] //[""]
7)Trim
func Trim(s string, cutset string) string 功能:在s字符串的头部和尾部去除cutset指定的字符串
fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! ")) //运行结果:["Achtung"]
8)Fields
func Fields(s string) []string 功能:去除s字符串的空格符,并且按照空格分割返回slice
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) //运行结果:Fields are: ["foo" "bar" "baz"]
1.2,字符串转换
字符串转化的函数在strconv中,如下也只是列出一些常用的。
1)Append
Append 系列函数将整数等转换为字符串后,添加到现有的字节数组中
str := make([]byte, 0, 100) str = strconv.AppendInt(str, 4567, 10) //以10进制方式追加 str = strconv.AppendBool(str, false) str = strconv.AppendQuote(str, "abcdefg") str = strconv.AppendQuoteRune(str, '单') fmt.Println(string(str)) //4567false"abcdefg"'单'
2)Format
Format 系列函数把其他类型的转换为字符串。
a := strconv.FormatBool(false) b := strconv.FormatInt(1234, 10) c := strconv.FormatUint(12345, 10) d := strconv.Itoa(1023) fmt.Println(a, b, c, d) //false 1234 12345 1023
3)Parse
Parse 系列函数把字符串转换为其他类型。
package main import ( "fmt" "strconv" ) func checkError(e error) { if e != nil { fmt.Println(e) } } func main() { a, err := strconv.ParseBool("false") checkError(err) b, err := strconv.ParseFloat("123.23", 64) checkError(err) c, err := strconv.ParseInt("1234", 10, 64) checkError(err) d, err := strconv.ParseUint("12345", 10, 64) checkError(err) e, err := strconv.Atoi("1023") checkError(err) fmt.Println(a, b, c, d, e) //false 123.23 1234 12345 1023 }
2,正则表达式
正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具。
详细的语法描述参考:http://code.google.com/p/re2/wiki/Syntax
如果strings包能解决你的问题,那么就尽量使用它来解决。因为他们足够简单、而且性能和可读性都会比正则好。
package main import ( "fmt" "regexp" ) func main() { context1 := "3.14 123123 .68 haha 1.0 abc 6.66 123." //MustCompile解析并返回一个正则表达式。如果成功返回,该Regexp就可用于匹配文本。 //解析失败时会产生panic // \d 匹配数字[0-9],d+ 重复>=1次匹配d,越多越好(优先重复匹配d) exp1 := regexp.MustCompile(`\d+\.\d+`) //返回保管正则表达式所有不重叠的匹配结果的[]string切片。如果没有匹配到,会返回nil。 //result1 := exp1.FindAllString(context1, -1) //[3.14 1.0 6.66] result1 := exp1.FindAllStringSubmatch(context1, -1) //[[3.14] [1.0] [6.66]] fmt.Printf("%v\n", result1) fmt.Printf("\n------------------------------------\n\n") context2 := ` <title>标题</title> <div>你过来啊</div> <div>hello mike</div> <div>你大爷</div> <body>呵呵</body> ` //(.*?)被括起来的表达式作为分组 //匹配<div>xxx</div>模式的所有子串 exp2 := regexp.MustCompile(`<div>(.*?)</div>`) result2 := exp2.FindAllStringSubmatch(context2, -1) //[[<div>你过来啊</div> 你过来啊] [<div>hello mike</div> hello mike] [<div>你大爷</div> 你大爷]] fmt.Printf("%v\n", result2) fmt.Printf("\n------------------------------------\n\n") context3 := ` <title>标题</title> <div>你过来啊</div> <div>hello mike go</div> <div>你大爷</div> <body>呵呵</body> ` exp3 := regexp.MustCompile(`<div>(.*?)</div>`) result3 := exp3.FindAllStringSubmatch(context3, -1) //[[<div>你过来啊</div> 你过来啊] [<div>你大爷</div> 你大爷]] fmt.Printf("%v\n", result3) fmt.Printf("\n------------------------------------\n\n") context4 := ` <title>标题</title> <div>你过来啊</div> <div>hello mike go</div> <div>你大爷</div> <body>呵呵</body> ` exp4 := regexp.MustCompile(`<div>(?s:(.*?))</div>`) result4 := exp4.FindAllStringSubmatch(context4, -1) /* [[<div>你过来啊</div> 你过来啊] [<div>hello mike go</div> hello mike go] [<div>你大爷</div> 你大爷]] */ fmt.Printf("%v\n", result4) fmt.Printf("\n------------------------------------\n\n") for _, text := range result4 { fmt.Println(text[0]) //带有div fmt.Println(text[1]) //不带带有div fmt.Println("================\n") } }
3,JSON处理
4,文件操作
4.1相关api
1)建立与打开文件
新建文件可以通过如下两个方法:
func Create(name string) (file *File, err Error) 根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666的文件,返回的文件对象是可读写的。 func NewFile(fd uintptr, name string) *File 根据文件描述符创建相应的文件,返回一个文件对象
通过如下两个方法来打开文件:
func Open(name string) (file *File, err Error) 该方法打开一个名称为name的文件,但是是只读方式,内部实现其实调用了OpenFile。 func OpenFile(name string, flag int, perm uint32) (file *File, err Error) 打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限
2)写文件
func (file *File) Write(b []byte) (n int, err Error) 写入byte类型的信息到文件 func (file *File) WriteAt(b []byte, off int64) (n int, err Error) 在指定位置开始写入byte类型的信息 func (file *File) WriteString(s string) (ret int, err Error) 写入string信息到文件
3)读文件
func (file *File) Read(b []byte) (n int, err Error) 读取数据到b中 func (file *File) ReadAt(b []byte, off int64) (n int, err Error) 从off开始读取数据到b中
4)删除文件
func Remove(name string) Error 调用该函数就可以删除文件名为name的文件
4.2,示例
1)写文件
package main import ( "fmt" "os" ) func main() { fout, err := os.Create("./xxx.txt") //新建文件 //fout, err := os.OpenFile("./xxx.txt", os.O_CREATE, 0666) if err != nil { fmt.Println(err) return } defer fout.Close() //main函数结束前, 关闭文件 for i := 0; i < 5; i++ { outstr := fmt.Sprintf("%s:%d\n", "Hello go", i) fout.WriteString(outstr) //写入string信息到文件 fout.Write([]byte("abcd\n")) //写入byte类型的信息到文件 } }
2)读文件
func main() { fin, err := os.Open("./xxx.txt") //打开文件 if err != nil { fmt.Println(err) } defer fin.Close() buf := make([]byte, 1024) //开辟1024个字节的slice作为缓冲 for { n, _ := fin.Read(buf) //读文件 if n == 0 { //0表示已经到文件结束 break } fmt.Println(string(buf)) //输出读取的内容 } }
3)拷贝文件
package main import ( "fmt" "io" "os" ) func main() { args := os.Args //获取用户输入的所有参数 //如果用户没有输入,或参数个数不够,则调用该函数提示用户 if args == nil || len(args) != 3 { fmt.Println("useage : xxx srcFile dstFile") return } srcPath := args[1] //获取输入的第一个参数 dstPath := args[2] //获取输入的第二个参数 fmt.Printf("srcPath = %s, dstPath = %s\n", srcPath, dstPath) if srcPath == dstPath { fmt.Println("源文件和目的文件名字不能相同") return } srcFile, err1 := os.Open(srcPath) //打开源文件 if err1 != nil { fmt.Println(err1) return } dstFile, err2 := os.Create(dstPath) //创建目的文件 if err2 != nil { fmt.Println(err2) return } buf := make([]byte, 1024) //切片缓冲区 for { //从源文件读取内容,n为读取文件内容的长度 n, err := srcFile.Read(buf) if err != nil && err != io.EOF { fmt.Println(err) break } if n == 0 { fmt.Println("文件处理完毕") break } //切片截取 tmp := buf[:n] //把读取的内容写入到目的文件 dstFile.Write(tmp) } //关闭文件 srcFile.Close() dstFile.Close() }