文件操作
字符串處理函數
字符串在開發中使用頻率較高,我們經常需要對字符串進行拆分、判斷等操作,可以借助Go標准庫中的strings包快速達到處理字符串的目錄。除Contains、Join、Trim、Replace等我們學過的字符串處理函數之外,以下函數也常常會被用到。
字符串分割
func Split(s, sep string) []string //功能:把s字符串按照sep分割,返回slice 參1:s,表示待拆分的字符串 參2:sep,表示分割符,該參數為string 類型 返回值:切片,存儲拆分好的子串
示例代碼:
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 Fields(s string) []string //功能:去除s字符串的空格符,並且按照空格分割,返回slice 參1:s,表示待拆分的字符串 返回值:切片,存儲拆分好的子串
示例代碼:
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) //運行結果:Fields are: ["foo" "bar" "baz"]
判斷字符串后綴
func HasSuffix(s, suffix string) bool 功能:判斷s字符串是否有后綴子串suffix 參1:s,表示待判定字符串 參2:suffix,表示前綴子串 返回值:true or false
示例代碼:
fmt.Printf("%v\n", strings.HasSuffix("World Cup.png", ".png")) //運行結果:true
判斷字符串前綴
func HasPrefix(s, prefix string) bool 功能:判斷s字符串是否有前綴子串suffix 參1:s,表示待判定字符串 參2:prefix,表示前綴子串 返回值:true or false
示例代碼:
fmt.Printf("%v\n", strings.HasPrefix("World Cup.png", "world")) //運行結果:false
文件操作常用API
建立與打開文件
新建文件可以通過如下兩個方法:
func Create(name string) (file *File, err Error) 根據提供的文件名創建新的文件,返回一個文件對象,默認權限是0666的文件,返回的文件對象是可讀寫的。

func main() { f, err := os.Create("C:/itcast/test.txt") if err != nil { fmt.Println("Create err:", err) return } defer f.Close() fmt.Println("create successful") }
通過如下兩個方法來打開文件:
func Open(name string) (file *File, err Error)

func main() { f, err := os.Open("C:/itcast/test.txt") if err != nil { fmt.Println("open err: ", err) return } defer f.Close() _, err = f.WriteString("hello world") if err != nil { fmt.Println("WriteString err: ", err) return } fmt.Println("open successful") }
Open()是以只讀權限打開文件名為name的文件,得到的文件指針file,只能用來對文件進行“讀”操作。如果我們有“寫”文件的需求,就需要借助Openfile函數來打開了。
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
OpenFile()可以選擇打開name文件的讀寫權限。這個函數有三個默認參數:
參1:name,表示打開文件的路徑。可使用相對路徑 或 絕對路徑
參2:flg,表示讀寫模式,常見的模式有:
O_RDONLY(只讀模式), O_WRONLY(只寫模式), O_RDWR(可讀可寫模式), O_APPEND(追加模式)。| O_CREATE (當有此參數,必須指定 參數3) 重要的是如果讀取目錄的話只能指定O_RDONLY模式!!!!
參3:perm,表權限取值范圍(0-7),表示如下:
0:沒有任何權限
1:執行權限(如果是可執行文件,是可以運行的)
2:寫權限
3: 寫權限與執行權限
4:讀權限
5: 讀權限與執行權限
6: 讀權限與寫權限
7: 讀權限,寫權限,執行權限

func main() { f, err := os.OpenFile("C:/itcast/test.txt", os.O_RDWR | os.O_CREATE, 0600) // 777--rwx rwx rwx if err != nil { fmt.Println("OpenFile err: ", err) return } defer f.Close() f.WriteString("hello world12345...") fmt.Println("open successful") }
關閉文件函數:
func (f *File) Close() error
寫文件
1.按照字符串寫:
func (file *File) WriteString(s string) (ret int, err Error) 寫入string信息到文件
f.WriteString
返回實際寫出的字節數
windows: 回車、換行。 \r\n
Linux: 回車、換行。 \n
2.指定位置寫入
1)Seek(): 獲取文件讀寫位置。 func (f *File) Seek(offset int64, whence int) (ret int64, err error) offset: 矢量。 正數,向文件末尾偏移。負數,向文件開頭偏移 whence: 偏移的起始位置。 io.SeekStart : 文件起始位置。 io.SeekCurrent : 文件當前位置。 io.SeekEnd: 文件末尾位置。 返回值 ret: 從文件起始位置到,讀寫位置的偏移量。 2)WriteAt(): 在指定位置寫入數據。, 通常搭配 Seek()用 func (f *File) WriteAt(b []byte, off int64) (n int, err error) b: 待寫入的數據內容 off:寫入的位置。(通常是 Seek函數的 返回值)
例子:

package main import ( "os" "fmt" "io" ) func main() { f, err := os.Create("./test.txt") if err != nil { fmt.Println("Create err:", err) return } defer f.Close() n, err := f.WriteString("hello world\r\n") if err != nil { fmt.Println("WriteString err:", err) return } fmt.Println("n = ", n) //off, err := f.Seek(5, io.SeekStart) off, err := f.Seek(-5, io.SeekEnd) if err != nil { fmt.Println("Seek err:", err) return } fmt.Println("off:", off) n, err = f.WriteAt([]byte("1111"), off) if err != nil { fmt.Println("WriteAt err:", err) return } fmt.Println("write successful") }
3.按字節寫--按字節讀 :重要!!!!! ---- 按字節處理文件。既可以處理文本也可以處理二進制文件(.jpg/mp3/avi....)
func (file *File) Read(b []byte) (n int, err Error)
b: 用來存儲讀到的數據的 緩沖區。
返回n:實際讀到的 字節數。
func (file *File) Write(b []byte) (n int, err Error)
b: 存儲數據的緩沖區,其中的數據即將被寫入文件。。
返回n:實際寫出的 字節數。

1 func main01() { 2 f, err := os.OpenFile("test.txt", os.O_RDWR, 0600) 3 if err != nil { 4 fmt.Println("Open err:", err) 5 return 6 } 7 defer f.Close() 8 9 buf := make([]byte, 4096) // 4k 10 11 n, err := f.Read(buf) 12 if err != nil { 13 fmt.Println("Read err:", err) 14 return 15 } 16 fmt.Printf("read data:%s", buf[:n]) 17 } 18 19 func main02() { 20 f, err := os.OpenFile("test.txt", os.O_RDWR, 0600) 21 if err != nil { 22 fmt.Println("Open err:", err) 23 return 24 } 25 defer f.Close() 26 27 n, err := f.Write([]byte("AAA")) 28 if err != nil { 29 fmt.Println("Write err:", err) 30 return 31 } 32 fmt.Println("n = ", n) 33 }
讀文件:bufio
按行讀。----- 處理文本文件。 1) 獲取一個 reader(自帶緩沖區) func NewReader(rd io.Reader) *Reader rd: 成功打開的文件指針。 f 返回值:Reader (閱讀器,自帶緩沖區) 2)從 reader 的緩沖區中獲取 指定數據 ReadBytes( '\n' ) func (b *Reader) ReadBytes(delim byte) ([]byte, error) delim :讀取數據的拆分依據。 返回值:成功獲取到的數據內容。 通常,會使用 for 來循環調用 ReadBytes, 一直讀到 err == io.EOF 的時候,結束信息。代表文件讀取完畢。

1 package main 2 3 import ( 4 "os" 5 "fmt" 6 "bufio" 7 "io" 8 ) 9 10 func main() { 11 f, err := os.Open("test.txt") 12 if err != nil { 13 fmt.Println("Open err:", err) 14 return 15 } 16 defer f.Close() 17 18 // 獲取閱讀器 reader, 自帶緩沖區(用戶緩沖)。 19 reader := bufio.NewReader(f) 20 21 for { // 循環讀取文件, 當 err == io.EOF 結束循環 22 // 使用 帶分割符的 函數,讀取指定數據 ‘\n’獲取一行 23 buf, err := reader.ReadBytes('\n') 24 // 成功讀取到的一行數據 保存在 buf中 25 fmt.Printf("buf:%s", buf) 26 if err != nil && err == io.EOF { 27 break 28 } 29 } 30 fmt.Println("文件讀取完畢") 31 }
讀目錄:
1) 打開目錄 OpenFile func OpenFile(name string, flag int, perm FileMode) (*File, error) flag: 只能指定 O_RDONLY perm : os.ModeDir ---> 操作目錄文件 返回: 操作目錄文件的 指針 2) 讀取目錄項 Readdir func (f *File) Readdir(n int) ([]FileInfo, error) n:讀取目錄項的個數。 -1 表全部 返回值:每一個目錄項 描述信息的(FileInfo) 切片 []FileInfo 切片 type FileInfo interface { Name() string // base name of the file Size() int64 // length in bytes for regular files; system-dependent for others 。。。 IsDir() bool // abbreviation for Mode().IsDir() 。。。 }

1 package main 2 3 import ( 4 "os" 5 "fmt" 6 ) 7 8 func main() { 9 var dir string 10 fmt.Print("請輸入一個待判定的目錄:") 11 fmt.Scan(&dir) 12 13 // 打開目錄 14 f, err := os.OpenFile(dir, os.O_RDONLY, os.ModeDir) 15 if err != nil { 16 fmt.Println("OpenFile err:", err) 17 return 18 } 19 defer f.Close() 20 21 // 讀取目錄項 -- 將一個目錄下的所有內容, 存入[]FileInfo 22 fileInfo, err := f.Readdir(-1) 23 if err != nil { 24 fmt.Println("Readdir err:", err) 25 return 26 } 27 28 // 依次取出目錄項 29 for _, dirInfo := range fileInfo { 30 if dirInfo.IsDir() { 31 fmt.Printf("%s 是一個 目錄\n", dirInfo.Name()) 32 } else { 33 fmt.Printf("%s is not 目錄\n", dirInfo.Name()) 34 } 35 } 36 37 }
練習例子
大文件拷貝實現:
1. 只讀打開文件 os.Open --> fr defer close() 2. 創建新文件 os.Create --> fw defer close() 3. for 循環安字節讀取 fr 中的所有數據, 存入 buf 4. 讀多少,寫多少,將buf 中數據寫入 fw 5. 判斷 err == io.EOF 來確認讀到文件末尾。

package main import ( "os" "fmt" "io" ) func main() { // 創建 待讀取的文件,和 待寫入的文件 f_r, err := os.Open("C:/itcast/01-結構體的定義和初始化.avi") if err != nil { fmt.Println("open err:", err) return } defer f_r.Close() f_w, err := os.Create("./test.avi") if err != nil { fmt.Println("Create err:", err) return } defer f_w.Close() buf := make([]byte, 4096) //創建緩沖區,存儲讀到的數據 // 循環從 f_r 對應文件中讀取數據, for { n, err := f_r.Read(buf) if err == io.EOF { fmt.Println("讀取文件完成") break } if err != nil { fmt.Println("Read err:", err) return } // 原封不動寫到 f_w 文件中, 讀多少,寫多少 n, err = f_w.Write(buf[:n]) if err != nil { fmt.Println("Write err:", err) return } } os.OpenFile() }
練習1 初級練習

func main() { //從用戶給出的目錄中,找出所有的 .jpg 文件 var path string fmt.Scan(&path) f,err:=os.OpenFile(path,os.O_RDONLY,os.ModeDir) if err!=nil{ fmt.Println(err) return } fileinfo,err:=f.Readdir(-1) if err!=nil{ fmt.Println("err",err) return } for _,i:=range fileinfo{ if strings.HasSuffix(i.Name(),"jpg"){ fmt.Println(i.Name()) } }
練習2 中級練習

package main import ( "fmt" "os" "strings" "io" ) func copyMp3ToDir(fileName, path string) { pathName := path + "/" + fileName fr, err := os.Open(pathName) // 打開 源文件 if err != nil { fmt.Println("Open err:", err) return } defer fr.Close() fw, err :=os.Create("./" + fileName) // 打開拷貝的文件 if err != nil { fmt.Println("Create err:", err) return } defer fw.Close() // 創建一個用於read 存儲數據的 buf buf := make([]byte, 4096) // 循環從 fr 中讀取數據, 原封不動 寫到 fw中 for { n, err := fr.Read(buf) if n == 0 { fmt.Println("文件拷貝完畢") break } if err != nil && err != io.EOF { fmt.Println("err:", err) } fw.Write(buf[:n]) // 讀多少,寫多少 } } func main() { // 請用戶指定 目錄 var path string fmt.Print("請輸入目錄位置:") fmt.Scan(&path) // 打開指定目錄位置 dir_fp, err := os.OpenFile(path, os.O_RDONLY, os.ModeDir) if err != nil { fmt.Println("Openfile err:", err) return } defer dir_fp.Close() // 讀取目錄項 dirsInfo, err := dir_fp.Readdir(-1) if err != nil { fmt.Println("Readdir err:", err) return } // 從目錄項[] 中提取每一個目錄項 for _, dir := range dirsInfo { fileName := dir.Name() // 根據后綴名,篩選文件 if strings.HasSuffix(fileName, ".mp3") { // 將該文件 copy 至指定目錄 copyMp3ToDir(fileName, path) //fmt.Println("mp3文件有:", fileName) } } }

//2.從用戶給出的目錄中,拷貝 .mp3文件到指定目錄中。 args:=os.Args f1,err:=os.OpenFile(args[1],os.O_RDONLY,os.ModeDir) if err!=nil{ fmt.Println(err) return } fmt.Println(args[1],args[2]) fileinfo,err:=f1.Readdir(-1) if err!=nil { fmt.Println(err) } for _,name:=range fileinfo{ //fmt.Println(name) if strings.HasSuffix(name.Name(),".mp3"){ fmt.Println(name.Name()) copyfile(args[1]+"/"+name.Name(),args[2]+"/"+name.Name()) } } defer f1.Close() } func copyfile(dst,src string){ buf:=make([]byte,4096) f1, err := os.OpenFile(dst, os.O_RDONLY, 0666) if err != nil { fmt.Println(err) return } fw, err := os.Create(src) if err != nil { fmt.Println(err) return } for { n, err := f1.Read(buf) if err != nil || err ==io.EOF{ fmt.Println(err) break } fw.Write(buf[:n]) } defer fw.Close()
練習3 高級練習

1 package main 2 3 import ( 4 "os" 5 "fmt" 6 "strings" 7 "bufio" 8 "io" 9 ) 10 11 func countLove(fileName, path string) int { 12 // 打開文件,txt 13 f, err := os.Open(path + "/" + fileName) 14 if err != nil { 15 fmt.Println("Open err:", err) 16 return -1 17 } 18 defer f.Close() 19 20 // 1 創建 reader 21 reader := bufio.NewReader(f) 22 var counter int = 0 23 24 // for 循環 按行讀取文件,--- this is a test for love --》[]string 25 for { 26 // 2 指定分隔符,按行提取數據 27 buf, err := reader.ReadBytes('\n') // buf中保存讀到的一行數據 28 if err != nil && err == io.EOF { 29 break 30 } 31 if err != nil { 32 fmt.Println("ReadBytes err:", err) 33 return -1 34 } 35 // 將一行數據中的所有單詞 拆分 36 words := strings.Fields(string(buf)) 37 for _, word := range words { 38 if word == "love" { 39 counter++ // 統計 個數。 40 } 41 } 42 } 43 fmt.Println("counter:", counter) 44 45 return counter 46 } 47 48 func main() { 49 50 // 測試統計 函數是否生效 51 //countLove("test.txt", "C:/itcast/test2") 52 53 // 請用戶指定 目錄 54 var path string 55 fmt.Print("請輸入目錄位置:") 56 fmt.Scan(&path) 57 58 // 打開指定目錄位置 59 dir_fp, err := os.OpenFile(path, os.O_RDONLY, os.ModeDir) 60 if err != nil { 61 fmt.Println("Openfile err:", err) 62 return 63 } 64 defer dir_fp.Close() 65 66 // 統計目錄下所有 txt 文件的 love 個數 67 var allLove int = 0 68 69 // 讀取目錄項 70 dirsInfo, err := dir_fp.Readdir(-1) 71 if err != nil { 72 fmt.Println("Readdir err:", err) 73 return 74 } 75 // 從目錄項[] 中提取每一個目錄項 76 for _, dir := range dirsInfo { 77 fileName := dir.Name() 78 // 根據后綴名,篩選文件 79 if strings.HasSuffix(fileName, ".txt") { 80 // 打開文件, 統計 該文件中有多少個 “love” 81 allLove += countLove(fileName, path) 82 } 83 } 84 fmt.Println("指定的目錄中,一共包含 love 個數:", allLove) 85 }

1 package main 2 3 import ( 4 "os" 5 "fmt" 6 "strings" 7 "bufio" 8 "io" 9 ) 10 11 func main() { 12 //統計指定目錄下,所有.txt文件中,“Love”這個單詞 出現的次數。 13 args:=os.Args 14 fdir,err:=os.OpenFile(args[1],os.O_RDONLY,os.ModeDir) 15 if err!=nil{ 16 fmt.Println(err) 17 return 18 } 19 fileinof,err:=fdir.Readdir(-1) 20 var txt []string 21 for _,info:=range fileinof{ 22 23 if strings.HasSuffix(info.Name(),".txt"){ 24 fmt.Println(info.Name()) 25 txt=append(txt, info.Name()) 26 } 27 } 28 for _,v:=range txt{ 29 prisetxt("love","D:/111/"+v) 30 } 31 } 32 //func dir(){} 33 func prisetxt(s string,txt string){ 34 35 f1,err:=os.Open(txt) 36 if err!=nil{ 37 fmt.Println(err) 38 } 39 reader:=bufio.NewReader(f1) 40 //conster :=0 41 for { 42 bytess, err := reader.ReadBytes('\n') 43 fmt.Println(string(bytess)) 44 con:=strings.Split(string(bytess),"love") 45 fmt.Println(len(con)-1) 46 if err != nil || err == io.EOF { 47 fmt.Println(err) 48 break 49 } 50 51 } 52 defer f1.Close() 53 //fmt.Println(conster) 54 55 }