天天看點

golang學習八: 檔案操作:字元串的處理, 字元串的類型轉換, 檔案操作一、字元串的處理:二、字元串的類型轉換:三、檔案操作:

文章目錄

  • 一、字元串的處理:
    • 1. strings包:
    • 2. Contains是否包含:
    • 3. Join: 字元串連接配接
    • 4. Index查找索引
    • 5. Repeat: 重複
    • 6. Replace:替換:
    • 7. Split: 分割
    • 8. Trim: 去除指定的字元串
    • 9. Fields: 去除空格
  • 二、字元串的類型轉換:
    • 1. strconv包:
    • 2. 字元串轉字元切片:
    • 3. Format: 把其他類型的轉換為字元串
    • 3. Parse: 把字元串轉換為其他類型:
    • 4. Append:
  • 三、檔案操作:
    • 1. 建立檔案:
    • 2. 寫入檔案:
    • 3. 打開檔案:
    • 4. 讀取檔案内容:
      • 按行讀取:
    • 5. 檔案操作案例:

一、字元串的處理:

1. strings包:

從檔案中将資料讀取出來後,很多情況下并不是将資料列印出來, 而是要做相對應的處理. 例如: 去掉空格等一些特殊符号, 對一些内容進行替換等;

這裡涉及到對一些字元串的處理, 需要借助于包"strings"

  • 常用的字元串處理函數:
    • Contains;
    • Join:
    • Index;
    • Repeat;
    • Replace
    • Split;
    • Trim;
    • Fields;

2. Contains是否包含:

文法:

功能:字元串s中是否包含substr,傳回bool值

import (
	"fmt"
	"strings"
)

func main() {
	str1 := "hello world"
	str2 := "h"

	// Contains(被查找的字元串, 查找的字元串)	傳回值: bool
	// 一般用于模糊查找
	b := strings.Contains(str1, str2)
	fmt.Println(b) // true
}
           

3. Join: 字元串連接配接

文法:

功能:字元串連結,把slicea通過sep連結起來

func main() {
	// 字元串切片
	slice := []string{"123", "abc", "456"}

	// Join(切片, "分隔符")
	str1 := strings.Join(slice, ",")
	fmt.Println(str1)	// 123,abc,456
}
           

4. Index查找索引

文法:

功能:在字元串s中查找sep所在的位置,傳回位置值,找不到傳回-1

func main() {
	str1 := "hello world"
	str2 := "g"
	str3 := "h"

	// Index(要查找的字元串, 查找内容): 查找一個字元串在另一個字元串中第一次出現的位置, 傳回值: int下标; -1表示找不到
	i1 := strings.Index(str1, str2)
	fmt.Println(i1) // -1

	i2 := strings.Index(str1, str3)
	fmt.Println(i2) // 0
}
           

5. Repeat: 重複

文法:

功能:重複s字元串count次,最後傳回重複的字元串

func main() {
	str := "hello world..."
	// 将一個字元串重複n次
	str1 := strings.Repeat(str, 5)
	fmt.Println(str1)	// hello world...hello world...hello world...hello world...hello world...
}
           

6. Replace:替換:

文法:

功能:在s字元串中,把old字元串替換為new字元串,n表示替換的次數,小于0表示全部替換

func main() {
	str := "一些敏感的詞彙的敏感"

	// 字元串替換, 屏蔽敏感詞彙
	str1 := strings.Replace(str, "敏感", "**", 1)
	fmt.Println(str1) // 一些**的詞彙的敏感

	// 如果替換次數小于0, 則表示全部替換
	str2 := strings.Replace(str, "敏感", "**", -1)
	fmt.Println(str2) // 一些**的詞彙的**
}
           

7. Split: 分割

文法:

功能:把s字元串按照sep分割,傳回slice

func main() {
	str1 := "130-188-1999"

	// 切割字元串
	slice := strings.Split(str1, "-")
	fmt.Println(slice)	// [130 188 1999]
}
           

8. Trim: 去除指定的字元串

文法:

功能:在s字元串的頭部和尾部去除cutset指定的字元串

func main() {
	str := "===are===U===OK==="
	// Trim: 去掉字元串指定的首位内容
	str1 := strings.Trim(str, "=")
	fmt.Println(str1)	// are===U===OK
}
           

9. Fields: 去除空格

文法:

功能:去除s字元串的空格符,并且按照空格分割傳回slice

func main() {
	str := "  are  U  ok  "

	// 去掉頭尾的空格, 一般用于統計單詞個數
	slice := strings.Fields(str)
	fmt.Println(slice)	// [are U ok]
}
           

二、字元串的類型轉換:

1. strconv包:

GO語言也提供了字元串與其它類型之間互相轉換的函數; 相應的字元串轉換函數都在"strconv"包

  • 字元串轉換:
    • Format;
    • Parse;
    • Append;

2. 字元串轉字元切片:

func main() {
	str := "hello world"
	// 将字元串轉成字元切片 => 強制類型轉換
	slice := []byte(str)

	fmt.Println(slice) // [104 101 108 108 111 32 119 111 114 108 100]
}
           

3. Format: 把其他類型的轉換為字元串

Format 系列函數把其他類型的轉換為字元串

func main() {
	// 字元串切片
	slice := []byte{'h', 'e', 'l', 'l', 'o', 97}
	fmt.Println(slice)         // [104 101 108 108 111 97]
	fmt.Println(string(slice)) // helloa

	// 将其他類型轉換成字元串
	b := false
	str1 := strconv.FormatBool(b)
	fmt.Println(str1)        // false
	fmt.Printf("%T\n", str1) // string

	str2 := strconv.FormatInt(140, 16) // 第二個參數是要轉化的進制(2, 8, 10, 16)
	fmt.Println(str2)                  // 8c
	fmt.Printf("%T\n", str2)           // string

	str3 := strconv.FormatFloat(3.141592, 'f', 4, 64)
	fmt.Println(str3)        // 3.1416
	fmt.Printf("%T\n", str3) // string

	str4 := strconv.Itoa(123)
	fmt.Println(str4)	// 123
}
           

3. Parse: 把字元串轉換為其他類型:

Parse 系列函數把字元串轉換為其他類型

func main() {
	// 将字元串轉成其他類型
	b1, err1 := strconv.ParseBool("true")
	fmt.Println(b1, err1)  // true <nil>
	fmt.Printf("%T\n", b1) // bool

	// 轉換失敗 傳回false
	b2, err2 := strconv.ParseBool("truee")
	fmt.Println(b2, err2)  // false strconv.ParseBool: parsing "truee": invalid syntax
	fmt.Printf("%T\n", b2) // bool

	v1, err3 := strconv.ParseInt("abc", 16, 64)
	fmt.Println(v1, err3)  // 2748 <nil>
	fmt.Printf("%T\n", v1) // int64

	v2, err4 := strconv.ParseFloat("3.14159", 64)
	fmt.Println(v2, err4)  // 3.14159 <nil>
	fmt.Printf("%T\n", v2) // float64
}
           

4. Append:

Append 系列函數将整數等轉換為字元串後,添加到現有的位元組數組中

func main() {
	// 将其他類型轉成字元串, 并且添加到字元切片裡
	slice := make([]byte, 0, 1024)

	slice = strconv.AppendBool(slice, false)
	slice = strconv.AppendInt(slice, 123, 2)
	slice = strconv.AppendFloat(slice, 3.14159, 'f', 4, 64)
	slice = strconv.AppendQuote(slice, "hello")
	fmt.Println(slice, string(slice))
	// [102 97 108 115 101 49 49 49 49 48 49 49 51 46 49 52 49 54 34 104 101 108 108 111 34] false11110113.1416"hello"
}
           

三、檔案操作:

1. 建立檔案:

将資料存儲到檔案之前, 先要建立檔案. GO語言中提供了一個Create()函數專門建立檔案.

該函數在建立檔案時, 首先會判斷要建立的檔案是否存在, 如果不存在, 則建立, 如果存在, 會先将檔案中已有的資料清空;

同時, 當檔案建立成功後, 該檔案會預設的打開, 是以不用在執行打開操作, 可以直接向該檔案中寫入資料;

  • 建立檔案的步驟:
    • 導入"os"包, 建立檔案, 讀寫檔案的函數都在該包;
    • 指定建立的檔案存放路徑以及檔案名;
    • 執行Create()函數, 進行檔案建立;
    • 關閉檔案;
package main

import (
	"fmt"
	"os"
)

func main() {
	// 傳回值 => 檔案指針 和 錯誤資訊
	fp, err := os.Create("./a.txt")
	if err != nil {
		//檔案建立失敗
		/*
		   1.路徑不存在
		   2.檔案權限
		   3.程式打開檔案上限
		*/
		fmt.Println("檔案建立失敗")
		return
	}

	// todo: 讀寫檔案

	//關閉檔案
	//如果打開檔案不關閉 造成記憶體的浪費  程式打開檔案的上限
	//fp.Close()
	defer fp.Close()
}
           

2. 寫入檔案:

檔案打開以後, 可以向檔案中寫資料, 可以使用WriteString()方法

package main

import (
	"fmt"
	"os"
)

func main() {
	//\反斜杠 轉義字元
	//在寫路徑時可以使用/正斜杠代替\反斜杠
	fp, err := os.Create("./a.txt")
	if err != nil {
		fmt.Println("檔案建立失敗")
		return
	}

	// TODO: 寫檔案
	// \n不會換行  原因 在windows文本檔案中換行\r\n  回車  在linux中換行\n
	fp.WriteString("hello world...\r\n")
	fp.WriteString("123456789...\r\n")

	defer fp.Close()
}
           
func main() {
	fp, err := os.Create("./a.txt")
	if err != nil {
		fmt.Println("檔案建立失敗")
		return
	}

	// TODO: 寫檔案
	// slice := []byte{'h', 'e', 'l', 'l', 'o'}
	// count, err := fp.Write(slice)	// 5
	count, err := fp.Write([]byte("好好學習, 天天向上")) // 26
	if err != nil {
		fmt.Println("寫入檔案失敗")
		return
	} else {
		fmt.Println(count)
	}

	defer fp.Close()
}
           
func main() {
	fp, err := os.Create("./a.txt")
	if err != nil {
		fmt.Println("檔案建立失敗")
		return
	}

	// TODO: 寫檔案
	// 擷取光标流位置
	// 擷取檔案起始位置到結尾有多少字元
	count, _ := fp.Seek(0, os.SEEK_END) // os.SEEK_END: 後續版本會取消
	fmt.Println(count)

	count1, _ := fp.Seek(0, io.SeekEnd)
	fmt.Println(count1) // 0

	// 按照指定位置寫入
	// func (f *File) WriteAt(b []byte, off int64) (n int, err error)
	fp.WriteAt([]byte("hello world"), count1)
	fp.WriteAt([]byte("哈"), 0) // 内容被覆寫了
	fp.WriteAt([]byte("真香"), 19)

	defer fp.Close()
}
           

3. 打開檔案:

// os.Open() 隻支援讀操作, 不能進行寫入操作
fp, err := os.Open("./a.txt")
           
func OpenFile(name string, flag int, perm FileMode) (*File, error)
           

說明:

  • OpenFile( )這個函數有三個參數,第一個參數表示打開檔案的路徑,第二個參數表示模式,常見的模式有:
    • O_RDONLY: 隻讀模式;
    • O_WRONLY: 隻寫模式;
    • O_RDWR: 可讀可寫模式;
    • O_APPEND: 追加模式;
  • 第三個參數, 表示權限, 取值範圍(0-7)表示如下:
說明
沒有任何權限
1 執行權限(如果是可執行檔案, 是可以運作的)
2 寫權限
3 寫權限與執行權限
4 讀權限
5 讀權限與執行權限
6 讀權限與寫權限
7 讀權限, 寫權限, 執行權限
func main() {
	// 打開存在的檔案
	// os.Open() 隻支援讀操作
	// fp, err := os.Open("./a.txt")

	// func OpenFile(name string, flag int, perm FileMode) (*File, error)

	fp, err := os.OpenFile("./a.txt", os.O_RDWR, 6)
	if err != nil {
		fmt.Println("打開檔案失敗...")
		return
	}

	// fp.WriteString("好好學習\r\n")
	fp.WriteAt([]byte("hahahah"), 30)

	defer fp.Close()
}
           

4. 讀取檔案内容:

Read 讀取檔案

如果檔案已經存在, 并且也已經有資料了, 那麼可以直接讀取該檔案中的内容;

讀取檔案的基本流程如下:

  • 打開要讀取的檔案;
  • 對檔案進行讀取;
  • 關閉檔案;
package main

import (
    "fmt"
    "io"
    "os"
)
func main() {
    //打開檔案
    fp, err := os.Open("D:/a.txt")
    if err != nil {
        fmt.Println("err=", err)
        return
    }

    buf := make([]byte, 1024*2) //2k大小
    //n代表從檔案讀取内容的長度
    n, err1 := fp.Read(buf)
    // io.EOF: 指檔案的末尾
    if err1 != nil && err1 != io.EOF {
        fmt.Println("err1=", err1)
        return
    }
    fmt.Println("buf=", string(buf[:n]))

    //關閉檔案
    defer fp.Close()
}
           

按行讀取:

方式一:

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func main() {
	fp, err := os.Open("./a.txt")
	if err != nil {
		fmt.Println("err=", err)
		return
	}

	// 建立緩沖區
	r := bufio.NewReader(fp)
	// 行讀取, 截取的标志 '\n'
	slice, _ := r.ReadBytes('\n')
	fmt.Println(string(slice))
	slice, _ = r.ReadBytes('\n')
	fmt.Println(string(slice))

	for {
		// 遇到\n就結束讀取, 但是\n也需要讀取
		buf, err1 := r.ReadBytes('\n')
		if err1 != nil || err1 == io.EOF {
			fmt.Println("error = ", err1)
			break
		}
		fmt.Println(string(buf))
	}

	//關閉檔案
	defer fp.Close()
}
           

方式二: 直接讀取字元串

func main() {
	fp, err := os.Open("./a.txt")
	if err != nil {
		fmt.Println("err=", err)
		return
	}

	// 建立緩沖區
	r := bufio.NewReader(fp)
	// 行讀取, 截取的标志 '\n'
	slice, _ := r.ReadBytes('\n')
	fmt.Println(string(slice))
	slice, _ = r.ReadBytes('\n')
	fmt.Println(string(slice))

	for {
		str, err1 := r.ReadString('\n')
		if err1 != nil && err1 == io.EOF {
			fmt.Println("error = ", err1)
			break
		}
		fmt.Println(str)

	}
	//關閉檔案
	defer fp.Close()
}
           

5. 檔案操作案例:

檔案拷貝,将已有的檔案複制一份,同時重新命名。

基本的思路:

  • 讓使用者輸入要拷貝的檔案的名稱(源檔案)以及目的檔案的名稱;
  • 建立目的檔案;
  • 打開源檔案,并且讀取該檔案中的内容;
  • 将從源檔案中讀取的内容寫到目的檔案中;
package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	var srcFilename string
	var dstFilename string

	fmt.Println("請輸入原檔案名稱:")
	fmt.Scan(&srcFilename)
	fmt.Println("請輸入目的檔案名稱:")
	fmt.Scan(&dstFilename)

	// 打開檔案
	fp, err := os.Open(srcFilename)
	fd, err1 := os.Create(dstFilename)
	if err != nil || err1 != nil {
		fmt.Println("打開檔案失敗...")
		return
	}
	//核心處理,從源檔案讀取内容,往目的檔案寫,讀多少寫多少
	buf := make([]byte, 4*1024) //4k大小臨時緩沖區
	for {
		n, err := fp.Read(buf)           //從源檔案讀取内容,每次讀取一部分
		if err != nil || err == io.EOF { //檔案讀取完畢
			break
		}
		//往目的檔案寫,讀多少寫多少
		fd.Write(buf[:n])
	}
	// 關閉檔案
	defer fp.Close()
	defer fd.Close()
}