文本處理 - 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
    複製代碼
相關文章
相關標籤/搜索