文本处理 - Go Web 开发实战笔记

概述

Web 开发中文本处理是重要的一部分,常常须要对输入或输出的内容进行处理,这里的文本包括字符串、数字、Json、XMl 等等。Go 语言对文本的处理有官方的标准库来支持。web

XML 处理

XML 做为一种传输和存储数据的格式已经十分普及。Go 语言标准库中有支持 XML 相关处理的包。正则表达式

解析 XML

经过 xml 包的 Unmarshal 函数解析 XML 文件。编程

func Unmarshal(data []byte, v interface{}) error
复制代码

Unmarshal 函数参数 data 接收的是 XML 数据流,v 是须要输出的结构,定义为 interface,也就是能够把 XML 转换为任意的格式。json

示例以下:数组

/goweb/src/documents/products.xml浏览器

<?xml version="1.0" encoding="utf-8"?>
<products count="2" country="中国">
    <product>
        <productName>小米手机</productName>
        <price>3000</price>
    </product>
    <product>
        <productName>华为手机</productName>
        <price>6000</price>
    </product>
</products>
复制代码

/goweb/src/documents/inputXML.gobash

package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
)

// struct tag
type Products struct {
	// 根节点名称
	XMLName xml.Name `xml:"products"`

	// 属性
	MyCount int `xml:"count,attr"`
	MyCountry string `xml:"country,attr"`

	// 子节点
	ProductArr []Product `xml:"product"`
}

type Product struct {
	XMLName xml.Name `xml:"product""` ProductName string `xml:"productName""`
	Price float64 `xml:"price"`
}

func main()  {
	// 打开文件
	file,err := os.Open("./src/documents/products.xml")
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	// 延迟关闭
	defer file.Close()

	// 读取文件
	data, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Printf("error: %v", err)
		return
	}

	Products := Products{}
	// 解析 XML
	err = xml.Unmarshal(data, &Products)
	if err != nil {
		fmt.Printf("error:%v", err)
		return
	}

	fmt.Println(Products.XMLName.Local)
	fmt.Println(Products.MyCount)
	fmt.Println(Products.MyCountry)

	for i:=0;i<len(Products.ProductArr);i++ {
		fmt.Println(Products.ProductArr[i].XMLName.Local)
		fmt.Println(Products.ProductArr[i].ProductName)
		fmt.Println(Products.ProductArr[i].Price)
	}
}
复制代码

执行以上程序后,服务器控制台输出:服务器

products
2
中国
product
小米手机
3000
product
华为手机
6000
复制代码

XML 本质上是一种树形的数据格式,能够定义与之匹配的 go 语言的 struct 类型,而后经过 xml.Unmarshal 来将 xml 中的数据解析成对应的 struct 对象。网络

输出 XML

经过 xml 包的 Marshal 和 MarshalIndent 函数生成 XML 文件。数据结构

func Marshal(v interface{}) ([]byte, error)
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
复制代码

这两个函数第一个参数是用来生成 XML 的结构定义类型数据,都是返回生成的 XML 数据流。

示例以下:

/goweb/src/documents/outputXML.go

package main

import (
	"encoding/xml"
	"fmt"
	"os"
)

// struct tag
type Products struct {
	// 根节点名称
	XMLName xml.Name `xml:"products"`

	// 属性
	MyCount int `xml:"count,attr"`
	MyCountry string `xml:"country,attr"`

	// 子节点
	ProductArr []Product `xml:"product"`
}

type Product struct {
	ProductName string `xml:"productName""` Price float64 `xml:"price"` } func main() { p := &Products{MyCount: 2, MyCountry: "中国"} p.ProductArr = append(p.ProductArr, Product{"小米手机", 3000}) p.ProductArr = append(p.ProductArr, Product{"华为手机", 6000}) output, err := xml.MarshalIndent(p, "  ", "    ") if err != nil { fmt.Printf("error: %v\n", err) } os.Stdout.Write([]byte(xml.Header)) os.Stdout.Write(output) } 复制代码

执行以上程序后,服务器控制台输出:

<?xml version="1.0" encoding="UTF-8"?>
  <products count="2" country="中国">
      <product>
          <productName>小米手机</productName>
          <price>3000</price>
      </product>
      <product>
          <productName>华为手机</productName>
          <price>6000</price>
      </product>
  </products>
复制代码

xml.MarshalIndent 或者 xml.Marshal 输出的信息都是不带 XML 头的,为了生成正确的 xml 文件,使用 xml 包预约义的 Header 变量:os.Stdout.Write([]byte(xml.Header))。

JSON 处理

JSON 是一种轻量级的数据交换格式,因为 JSON 比 XML 更小、更快、更易解析,以及浏览器的内建快速解析支持,使得其更适用于网络数据传输领域。Go 语言的标准库已经很是好的支持了JSON,能够很容易的对 JSON 数据进行编、解码的工做。

解析 JSON

经过 JSON 包的 Unmarshal 函数解析 XML 文件。

func Unmarshal(data []byte, v interface{}) error
复制代码
  • 处理数组 JSON 文档示例:

    /goweb/src/documents/array.json

    [{
      "productName": "特斯拉",
      "price": 1000000
    }, {
      "productName": "iphone10",
      "price": 9999
    }]
    复制代码

    /goweb/src/documents/arryJson.go

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"io/ioutil"
    	"os"
    )
    
    // struct tag
    type MyProduct struct {
    	ProductName string
    	Price float64
    }
    
    type MyProducts []MyProduct
    
    func main()  {
    	// 打开文件
    	file,err := os.Open("./src/documents/array.json")
    	if err != nil {
    		fmt.Printf("error: %v", err)
    		return
    	}
    
    	// 延迟关闭
    	defer file.Close()
    
    	// 读取文件
    	data, err := ioutil.ReadAll(file)
    	if err != nil {
    		fmt.Printf("error: %v", err)
    		return
    	}
    
    	var p MyProducts
    	// 解析 JSON
    	json.Unmarshal(data, &p)
    	for i:=0;i<len(p);i++{
    		fmt.Println("产品名称:" + p[i].ProductName)
    		fmt.Printf("产品价格:%2f\n",p[i].Price)
    	}
    }
    复制代码

    执行以上程序后,服务器控制台输出:

    产品名称:特斯拉
    产品价格:1000000.000000
    产品名称:iphone10
    产品价格:9999.000000
    复制代码

    以上 arryJson.go 文件中的 MyProduct 结构体,若是不使用 tag,必须保证 struct 中的属性名和 json 文档对应的属性名相同(大小写不敏感),而且保证 struct 中的属性名首字母大写。

    若是名字不一致,须要使用 tag 进行映射。tag 自己也是大小写不敏感的,以下:

    [{"productName1": "特斯拉", "price": 1000000},{"productName1": "iphone10","price": 9999}]
    ...
    type MyProduct struct {
    	ProductName string `json:"productName1"`
    	Price float64
    }
    复制代码
  • 处理对象 JSON 文档示例:

    /goweb/src/documents/obj.json

    {
      "products": [{
        "productName": "特斯拉",
        "price": 1000000
      }, {
        "productName": "iphone10",
        "price": 9999
      }],
      "count": 2,
      "country": "美国"
    }
    复制代码

    /goweb/src/documents/objJson.go

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"io/ioutil"
    	"os"
    )
    
    // struct tag
    type MyProdct1 struct {
    	ProductName string
    	Price float64
    }
    
    type MyProducts1 struct {
    	Products []MyProdct1
    	Count int
    	Country string
    }
    
    func main()  {
    	// 打开文件
    	file,err := os.Open("./src/documents/obj.json")
    	if err != nil {
    		fmt.Printf("error: %v", err)
    		return
    	}
    
    	// 延迟关闭
    	defer file.Close()
    
    	// 读取文件
    	data, err := ioutil.ReadAll(file)
    	if err != nil {
    		fmt.Printf("error: %v", err)
    		return
    	}
    
    	var p MyProducts1
    	// 解析 JSON
    	json.Unmarshal(data, &p)
    
    	fmt.Println(p.Count)
    	fmt.Println(p.Country)
    
    	for i:=0;i<len(p.Products);i++{
    		fmt.Println("产品名称:" + p.Products[i].ProductName)
    		fmt.Printf("产品价格:%2f\n",p.Products[i].Price)
    	}
    }
    复制代码

    执行以上程序后,服务器控制台输出:

    2
    美国
    产品名称:特斯拉
    产品价格:1000000.000000
    产品名称:iphone10
    产品价格:9999.000000
    复制代码
  • 将 JSON 文档映射到 interface{} 上示例:

    /goweb/src/documents/jsonToInterface.go

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"io/ioutil"
    	"os"
    )
    
    // struct tag
    type MyProdct2 struct {
    	ProductName string
    	Price float64
    }
    
    type MyProducts2 struct {
    	Products []MyProdct2
    	Count int
    	Country string
    }
    
    func main()  {
    	// 打开文件
    	file,err := os.Open("./src/documents/obj.json")
    	if err != nil {
    		fmt.Printf("error: %v", err)
    		return
    	}
    
    	// 延迟关闭
    	defer file.Close()
    
    	// 读取文件
    	data, err := ioutil.ReadAll(file)
    	if err != nil {
    		fmt.Printf("error: %v", err)
    		return
    	}
    
    	var p interface{}
    	// 解析 JSON
    	json.Unmarshal(data, &p)
    	fmt.Println(p)
    	pp := p.(map[string]interface{})
    
    	fmt.Println(pp["count"])
    	fmt.Println(pp["country"])
    	fmt.Println(pp["products"])
    
    	products := pp["products"].([]interface{})
    
    	for i:=0;i<len(products);i++{
    		product := products[i].(map[string]interface{})
    		fmt.Println(product["productName"])
    		fmt.Printf("%.2f\n", product["price"])
    	}
    }
    复制代码

    执行以上程序后,服务器控制台输出:

    map[products:[map[productName:特斯拉 price:1e+06] map[productName:iphone10 price:9999]] count:2 country:美国]
    2
    美国
    [map[productName:特斯拉 price:1e+06] map[price:9999 productName:iphone10]]
    特斯拉
    1000000.00
    iphone10
    9999.00
    复制代码

    由于 interface{} 能够用来存储任意数据类型的对象,因此这种数据结构正好用于存储解析的未知结构的 json 数据的结果。JSON 包中采用 map[string]interface{} 和 []interface{} 结构来存储任意的 JSON 对象和数组。Go 类型和 JSON 类型的对应关系以下:

    bool 表明 JSON booleans,
    float64 表明 JSON numbers,
    string 表明 JSON strings,
    nil 表明 JSON null。

生成 JSON

经过 JSON 包的 Marshal 函数生成 JSON 文件。

func Marshal(v interface{}) ([]byte, error)
复制代码

/goweb/src/documents/outputJSON.go

package main

import (
	"encoding/json"
	"fmt"
)

// struct tag
type MyProdct struct {
	ProductName string
	Price float64
}

type MyProducts struct {
	Products []MyProdct
	Count int
	Country string
}

func main() {
	var p MyProducts
	p.Count = 2
	p.Country = "美国"
	p.Products = append(p.Products, MyProdct{ProductName: "特斯拉", Price: 1000000})
	p.Products = append(p.Products, MyProdct{ProductName: "iphone10", Price: 9999})
	b, err := json.Marshal(p)
	if err != nil {
		fmt.Println("json err:", err)
	}
	fmt.Println(string(b))
}
复制代码

执行以上程序后,服务器控制台输出:

{"Products":[{"ProductName":"特斯拉","Price":1000000},{"ProductName":"iphone10","Price":9999}],"Count":2,"Country":"美国"}
复制代码

上面输出字段名的首字母都是大写的,若是想用小写的首字母,就必须经过 struct tag 定义来实现:

type MyProdct struct {
	ProductName string `json:"productName"`
	Price float64 `json:"price"`
}

type MyProducts struct {
	Products []MyProdct `json:"products"`
	Count int `json:"count"`
	Country string `json:"country"`
}
复制代码

修改后输出:

{"products":[{"productName":"特斯拉","price":1000000},{"productName":"iphone10","price":9999}],"count":2,"country":"美国"}
复制代码

针对 JSON 的输出,在定义 struct tag 的时候须要注意的几点是:

  • 字段的 tag 是 "-",那么这个字段不会输出到 JSON
  • tag 中带有自定义名称,那么这个自定义名称会出如今 JSON 的字段名中,例如上面例子中 productName
  • tag 中若是带有 "omitempty" 选项,那么若是该字段值为空,就不会输出到 JSON 串中
  • 若是字段类型是 bool, string, int, int64 等,而 tag 中带有 ",string" 选项,那么这个字段在输出到 JSON 的时候会把该字段对应的值转换成 JSON 字符串

示例以下:

type Server struct {
    // ID 不会导出到JSON中
    ID int `json:"-"`

    // ServerName 的值会进行二次JSON编码
    ServerName  string `json:"serverName"`
    ServerName2 string `json:"serverName2,string"`

    // 若是 ServerIP 为空,则不输出到JSON串中
    ServerIP   string `json:"serverIP,omitempty"`
}

s := Server {
    ID:         3,
    ServerName:  `Go "1.0" `,
    ServerName2: `Go "1.0" `,
    ServerIP:   ``,
}
b, _ := json.Marshal(s)
os.Stdout.Write(b)
复制代码

会输出如下内容:

{"serverName":"Go \"1.0\" ","serverName2":"\"Go \\\"1.0\\\" \""}
复制代码

Marshal 函数只有在转换成功的时候才会返回数据,在转换的过程当中须要注意几点:

  • JSON 对象只支持 string 做为 key,因此要编码一个 map,那么必须是 map[string]T 这种类型( T 是 Go 语言中任意的类型)
  • Channel, complex 和 function 是不能被编码成 JSON 的
  • 嵌套的数据是不能编码的,否则会让 JSON 编码进入死循环
  • 指针在编码的时候会输出指针指向的内容,而空指针会输出 null

正则处理

正则表达式一般被用来检索、替换那些符合某个模式(规则)的文本。Go 语言经过 regexp 标准包为正则表达式提供了官方支持。

经过正则判断是否匹配

regexp 包中含有三个函数用来判断是否匹配,若是匹配返回 true,不然返回 false。

func Match(pattern string, b []byte) (matched bool, error error)
func MatchReader(pattern string, r io.RuneReader) (matched bool, error error)
func MatchString(pattern string, s string) (matched bool, error error)
复制代码

上面的三个函数实现了同一个功能,就是判断 pattern 是否和输入源匹配,匹配的话就返回 true,若是解析正则出错则返回 error。三个函数的输入源分别是 byte slice、RuneReader 和 string。

示例:

/Users/play/goweb/src/documents/RegExp1.go

package main

import (
	"fmt"
	"regexp"
)

/*
用正则表达式匹配文本

IP:^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$
Email: ^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+.(com|com.cn|net|org|cn)$

regexp MatchString(正则表达式,待匹配待字符串) 若是匹配成功,返回 true, 不然返回false
*/

// 判断是不是 IP 地址
func IsIP(ip string) (b bool) {
	if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", ip); !m {
		return false
	}
	return true
}

// 判断是不是 邮箱
func IsEmail(em string) (b bool) {
	if m, _ := regexp.MatchString("^[a-zA-Z0-9-_]+@[a-zA-Z0-9-_]+.(com|com.cn|net|org|cn)$", em); !m {
		return false
	}
	return true
}

func main()  {
	ip1 := "192.168.1.1"
	ip2 := "192.168.1.a"
	b1 := IsIP(ip1)
	b2 := IsIP(ip2)
	fmt.Println("192.168.1.1 是不是 IP 地址:",b1)
	fmt.Println("192.168.1.1 是不是 IP 地址:",b2)

	em1 := "abc@163.com"
	em2 := "abc.com"
	b3 := IsEmail(em1)
	b4 := IsEmail(em2)
	fmt.Println("192.168.1.1 是不是邮箱:",b3)
	fmt.Println("192.168.1.1 是不是邮箱:",b4)
}
复制代码

执行以上程序后,服务器控制台输出:

192.168.1.1 是不是 IP 地址: true
192.168.1.1 是不是 IP 地址: false
192.168.1.1 是不是邮箱: true
192.168.1.1 是不是邮箱: false
复制代码

经过正则获取内容

Match 模式只能用来对字符串的判断,而没法截取字符串的一部分、过滤字符串、或者提取出符合条件的一批字符串。若是想要知足这些需求,那就须要使用正则表达式的复杂模式。

示例:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
)

/*
用正则表达式替换文本

regexp.Compile
re.ReplaceAllStringFunc(src,target)

*/

func main()  {
	resp, err := http.Get("http://www.jd.com")
	if err != nil {
		fmt.Println("http get error.")
	}
	// 延迟关闭
	defer resp.Body.Close()

	// 读取内容
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("http read error")
		return
	}

	// 转化成字符串
	src := string(body)

	// 将 HTML 标签全转换成小写
	// \s: 匹配任何的空白符(空格、制表符、换页符等)
	// \S: 匹配任何非空白符
	re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
	src = re.ReplaceAllStringFunc(src, strings.ToLower)

	// 去除 STYLE
	re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
	src = re.ReplaceAllString(src, "")

	// 去除 SCRIPT
	re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
	src = re.ReplaceAllString(src, "")

	// 去除全部尖括号内的HTML代码,并换成换行符
	re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
	src = re.ReplaceAllString(src, "\n")

	// 去除连续的换行符
	re, _ = regexp.Compile("\\s{2,}")
	src = re.ReplaceAllString(src, "\n")

	fmt.Println(strings.TrimSpace(src))
}
复制代码

从以上示例能够看出,使用复杂的正则首先是 Compile,它会解析正则表达式是否合法,若是正确,那么就会返回一个 Regexp,而后就能够利用返回的 Regexp 在任意的字符串上面执行须要的操做。

解析正则表达式的有以下几个方法:

func Compile(expr string) (*Regexp, error)
func CompilePOSIX(expr string) (*Regexp, error)
func MustCompile(str string) *Regexp
func MustCompilePOSIX(str string) *Regexp
复制代码

CompilePOSIX 和 Compile 的不一样点在于 POSIX 必须使用 POSIX 语法,它使用最左最长方式搜索,而 Compileb 则只采用最左方式搜索(例如 [a-z]{2,4} 这样一个正则表达式,应用于 "aa09aaa88aaaa" 这个文本串时,CompilePOSIX 返回了 aaaa,而 Compile 的返回的是 aa)。前缀有 Must 的函数表示,在解析正则语法的时候,若是匹配模式串不知足正确的语法则直接 panic,而不加 Must 的则只是返回错误。

正则表达式的查找函数

func (re *Regexp) Find(b []byte) []byte
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllString(s string, n int) []string
func (re *Regexp) FindAllStringIndex(s string, n int) [][]int
func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string
func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int
func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte
func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int
func (re *Regexp) FindIndex(b []byte) (loc []int)
func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int)
func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int
func (re *Regexp) FindString(s string) string
func (re *Regexp) FindStringIndex(s string) (loc []int)
func (re *Regexp) FindStringSubmatch(s string) []string
func (re *Regexp) FindStringSubmatchIndex(s string) []int
func (re *Regexp) FindSubmatch(b []byte) [][]byte
func (re *Regexp) FindSubmatchIndex(b []byte) []int
复制代码

使用示例:

package main

import (
	"fmt"
	"regexp"
)

func main() {
	a := "I am learning Go language"

	re, _ := regexp.Compile("[a-z]{2,4}")

	//查找符合正则的第一个
	one := re.Find([]byte(a))
	fmt.Println("Find:", string(one))

	//查找符合正则的全部slice,n小于0表示返回所有符合的字符串,否则就是返回指定的长度
	all := re.FindAll([]byte(a), -1)
	fmt.Println("FindAll:", all)
	fmt.Println("FindAll:", string(all[0]))
	fmt.Println("FindAll:", string(all[1]))
	fmt.Println("FindAll:", string(all[2]))

	//查找符合条件的index位置,开始位置和结束位置
	index := re.FindIndex([]byte(a))
	fmt.Println("FindIndex:", index)

	//查找符合条件的全部的index位置,n同上
	allindex := re.FindAllIndex([]byte(a), -1)
	fmt.Println("FindAllIndex:", allindex)

	re2, _ := regexp.Compile("am(.*)lang(.*)")

	//查找Submatch,返回数组,第一个元素是匹配的所有元素,第二个元素是第一个()里面的,第三个是第二个()里面的
	//下面的输出第一个元素是"am learning Go language"
	//第二个元素是" learning Go ",注意包含空格的输出
	//第三个元素是"uage"
	submatch := re2.FindSubmatch([]byte(a))
	fmt.Println("FindSubmatch:", submatch)
	for _, v := range submatch {
		fmt.Println(string(v))
	}

	//定义和上面的FindIndex同样
	submatchindex := re2.FindSubmatchIndex([]byte(a))
	fmt.Println("submatchindex:", submatchindex)

	//FindAllSubmatch,查找全部符合条件的子匹配
	submatchall := re2.FindAllSubmatch([]byte(a), -1)
	fmt.Println("submatchall:",submatchall)

	//FindAllSubmatchIndex,查找全部字匹配的index
	submatchallindex := re2.FindAllSubmatchIndex([]byte(a), -1)
	fmt.Println("submatchallindex:",submatchallindex)
}

复制代码

文件操做

在 Web 编程中,文件操做在 Web 应用中是必须的、很是有用的,常常须要生成文件目录、文件(夹)编辑等操做。

目录操做

文件操做的大多数函数都是在 os 包里面,下面列举了几个目录操做的:

  • func Mkdir(name string, perm FileMode) error
    建立名称为 name 的目录,权限设置是 perm,例如 0777

  • func MkdirAll(path string, perm FileMode) error
    根据 path 建立多级子目录,例如 astaxie/test1/test2。

  • func Remove(name string) error
    删除名称为 name 的目录,当目录下有文件或者其余目录是会出错

  • func RemoveAll(path string) error
    根据 path 删除多级子目录,若是 path 是单个名称,那么该目录下的子目录所有删除。

代码示例:

package main

import (
	"fmt"
	"os"
)

func main() {
	// 建立目录
	os.Mkdir("mydir", 0777)

	// 建立多级子目录
	os.MkdirAll("mydir/test1/test2", 0777)

	// 待删除的目录必须为空
	err := os.Remove("mydir")
	if err != nil {
		fmt.Println(err)
	}

	// 能够删除不为空的目录
	os.RemoveAll("mydir")
}
复制代码

文件操做

新建文件
  • 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 是权限

写文件
  • 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 信息到文件

写文件的示例代码:

package main

import (
	"fmt"
	"os"
)

func main() {
	userFile := "hello.txt"
	fout, err := os.Create(userFile)
	if err != nil {
		fmt.Println(userFile, err)
		return
	}
	defer fout.Close()
	for i := 0; i < 4; i++ {
		fout.WriteString("Hello world\r\n")
		fout.Write([]byte("How are you\r\n"))
	}
}
复制代码

执行以上程序后,生成文件 hello.txt ,文件内容:

Hello world
How are you
Hello world
How are you
Hello world
How are you
Hello world
How are you
复制代码
读文件
  • 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 中

读文件的示例代码:

package main

import (
	"fmt"
	"os"
)

func main() {
	userFile := "hello.txt"
	fl, err := os.Open(userFile)
	if err != nil {
		fmt.Println(userFile, err)
		return
	}
	defer fl.Close()
	buf := make([]byte, 1024)
	for {
		n, _ := fl.Read(buf)
		if 0 == n {
			break
		}
		os.Stdout.Write(buf[:n])
	}
}
复制代码

执行以上程序后,读取文件 hello.txt ,文件内容:

Hello world
How are you
Hello world
How are you
Hello world
How are you
Hello world
How are you
复制代码
删除文件

Go语言里面删除文件和删除文件夹是同一个函数:

  • func Remove(name string) Error
    调用该函数就能够删除文件名为name的文件

字符串处理

Web 开发中常常须要对字符串进行分割、链接、转换等操做,Go 标准库中的 strings 和 strconv 两个包中的函数支持对字符串进行有效快速的操做。

字符串操做

  • 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
    复制代码
  • func Join(a []string, sep string) string
    字符串连接,把 slice a 经过 sep 连接起来

    s := []string{"foo", "bar", "baz"}
    fmt.Println(strings.Join(s, ", "))
    // foo, bar, baz   
    复制代码
  • func Index(s, sep string) int
    在字符串 s 中查找 sep 所在的位置,返回位置值,找不到返回-1

    fmt.Println(strings.Index("chicken", "ken"))
    fmt.Println(strings.Index("chicken", "dmr"))
    // 4
    // -1
    复制代码
  • func Repeat(s string, count int) string
    重复 s 字符串 count 次,最后返回重复的字符串

    fmt.Println("ba" + strings.Repeat("na", 2))
    // banana
    复制代码
  • 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
    复制代码
  • 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" " "]
    // [""]
    复制代码
  • func Trim(s string, cutset string) string
    在 s 字符串的头部和尾部去除 cutset 指定的字符串

    fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
    // ["Achtung"]
    复制代码
  • func Fields(s string) []string
    去除 s 字符串的空格符,而且按照空格分割返回 slice

    fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
    // Fields are: ["foo" "bar" "baz"]
    复制代码

字符串转换

  • Append 系列函数将整数等转换为字符串后,添加到现有的字节数组中。

    str := make([]byte, 0, 100)
    str = strconv.AppendInt(str, 4567, 10)
    str = strconv.AppendBool(str, false)
    str = strconv.AppendQuote(str, "abcdefg")
    str = strconv.AppendQuoteRune(str, '单')
    fmt.Println(string(str))
    
    // 输出:4567false"abcdefg"'单'
    复制代码
  • Format 系列函数把其余类型的转换为字符串

    a := strconv.FormatBool(false)
    b := strconv.FormatFloat(123.23, 'g', 12, 64)
    c := strconv.FormatInt(1234, 10)
    d := strconv.FormatUint(12345, 10)
    e := strconv.Itoa(1023)
    fmt.Println(a, b, c, d, e)
    
    // 输出:false 123.23 1234 12345 1023
    复制代码
  • Parse 系列函数把字符串转换为其余类型

    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
    复制代码
相关文章
相关标签/搜索