一、打開文件和關閉文件
os包File結構體的兩個方法:
func Open(name string) (file *File, err error)
Open打開一個文件用於讀取。如果操作成功,返回的文件對象的方法可用於讀取數據;對應的文件描述符具有O_RDONLY模式。如果出錯,錯誤底層類型是*PathError。
func (f *File) Close() error
Close關閉文件f,使文件不能用於讀寫。它返回可能出現的錯誤。

import ( "fmt" "os" ) func main() { // 打開文件 file, err := os.Open("e:/a.txt") if err != nil { fmt.Printf("打開文件出錯:%v\n", err) } fmt.Println(file) // &{0xc00006a780} // 關閉文件 err = file.Close() if err != nil { fmt.Printf("關閉文件出錯:%v\n", err) } }
二、讀文件
讀取文件內容並顯示在終端
方式一:(帶緩沖方式)

import ( "bufio" "fmt" "io" "os" ) func main() { // 打開文件 file, err := os.Open("e:/a.txt") if err != nil { fmt.Printf("打開文件出錯:%v\n", err) } // 及時關閉文件句柄 defer file.Close() // bufio.NewReader(rd io.Reader) *Reader reader := bufio.NewReader(file) // 循環讀取文件的內容 for { line, err := reader.ReadString('\n') // 讀到一個換行符就結束 if err == io.EOF { // io.EOF表示文件的末尾 break } // 輸出內容 fmt.Print(line) } }
方式二:一次性將整個文件讀入到內存中,這種方式適用於文件不大的情況。(使用 io/ioutil.ReadFile 方法)
func ReadFile(filename string) ([]byte, error)
ReadFile 從filename指定的文件中讀取數據並返回文件的內容。成功的調用返回的err為nil而非EOF。因為本函數定義為讀取整個文件,它不會將讀取返回的EOF視為應報告的錯誤。

import ( "fmt" "io/ioutil" ) func main() { // 使用 io/ioutil.ReadFile 方法一次性將文件讀取到內存中 filePath := "e:/.txt" content, err := ioutil.ReadFile(filePath) if err != nil { // log.Fatal(err) fmt.Printf("讀取文件出錯:%v", err) } fmt.Printf("%v\n", content) fmt.Printf("%v\n", string(content)) }
三、寫文件
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
OpenFile是一個更一般性的文件打開函數,大多數調用者都應用Open或Create代替本函數。它會使用指定的選項(如O_RDONLY等)、指定的模式(如0666等)打開指定名稱的文件。如果操作成功,返回的文件對象可用於I/O。如果出錯,錯誤底層類型是*PathError。
- 參數二:文件打開模式(可以組合);
- 參數三:用來在linux、unix系統下進行權限控制的。
os包的一些常量:
const ( O_RDONLY int = syscall.O_RDONLY // 只讀模式打開文件 O_WRONLY int = syscall.O_WRONLY // 只寫模式打開文件 O_RDWR int = syscall.O_RDWR // 讀寫模式打開文件 O_APPEND int = syscall.O_APPEND // 寫操作時將數據附加到文件尾部 O_CREATE int = syscall.O_CREAT // 如果不存在將創建一個新文件 O_EXCL int = syscall.O_EXCL // 和O_CREATE配合使用,文件必須不存在 O_SYNC int = syscall.O_SYNC // 打開文件用於同步I/O O_TRUNC int = syscall.O_TRUNC // 如果可能,打開時清空文件 )
寫文件操作應用實例
示例一:
- 創建一個新文件,寫入3行:"Hello World"
- 打開一個存在的文件,將原來的內容覆蓋成新的內容,3行:"你好,世界"
- 打開一個存在的文件,在原來的內容基礎上,追加3行:"你好,Golang"
- 打開一個存在的文件,將原來的內容讀出顯示在終端,並且追加3行:"你好,World"

import ( "bufio" "fmt" "os" ) func main() { filePath := "e:/a.txt" // 此文件事先不存在 file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE, 0666) // O_CREATE 能創建文件 if err != nil { fmt.Printf("打開文件出錯:%v", err) return } // 及時關閉文件句柄 defer file.Close() // 准備寫入的內容 str := "Hello World\r\n" // 寫入時,使用帶緩沖方式的 bufio.NewWriter(w io.Writer) *Writer writer := bufio.NewWriter(file) // 使用for循環寫入內容 for i := 0; i < 3; i++ { _, err := writer.WriteString(str) // func (b *Writer) WriteString(s string) (int, error) if err != nil { fmt.Printf("文件寫入出錯:%s", err) } } // 因為 writer 是帶緩存的,所以需要 Flush 方法將緩沖中的數據真正寫入到文件中 _ = writer.Flush() }
2:在1中修改,將 O_CREATE 修改為 O_TRUNC 模式即可,表示:打開文件並清空內容
3:在2中修改,將 O_TRUNC 修改為 O_APPEND 模式即可,表示:打開文件並在最后追加內容

import ( "bufio" "fmt" "io" "os" ) func main() { filePath := "e:/a.txt" file, err := os.OpenFile(filePath, os.O_RDWR | os.O_APPEND, 0666) if err != nil { fmt.Printf("打開文件出錯:%v", err) return } defer file.Close() // 先讀取原來文件的內容,並顯示在終端 reader := bufio.NewReader(file) for { str, err := reader.ReadString('\n') // 讀到一個換行符就結束 if err == io.EOF { // io.EOF表示文件的末尾 break } // 輸出內容 fmt.Print(str) } // 准備寫入的內容 str := "你好,World\r\n" // 寫入時,使用帶緩沖方式的 bufio.NewWriter(w io.Writer) *Writer writer := bufio.NewWriter(file) // 使用for循環寫入內容 for i := 0; i < 3; i++ { _, err := writer.WriteString(str) // func (b *Writer) WriteString(s string) (int, error) if err != nil { fmt.Printf("文件寫入出錯:%s", err) } } // 因為 writer 是帶緩存的,所以需要 Flush 方法將緩沖中的數據真正寫入到文件中 _ = writer.Flush() }
示例二:將一個文件內容,寫入到另一個文件中。(這兩個文件已存在)
這里使用 io/ioutil 的兩個方法,ReadFile 和 WriteFile:

import ( "fmt" "io/ioutil" ) func main() { filePath1 := "e:/a.txt" filePath2 := "e:/b.txt" content, err := ioutil.ReadFile(filePath1) if err != nil { fmt.Printf("讀取文件出錯:%v", err) return } err = ioutil.WriteFile(filePath2, content, 0666) if err != nil { fmt.Printf("寫入文件出錯:%v", err) return } }
四、判斷文件是否存在
golang判斷文件或文件夾是否存在的方法為使用 os.Stat() 函數返回的錯誤值進行判斷:
- 如果返回的錯誤為 nil,說明文件或文件夾存在;
- 如果返回的錯誤類型使用 os.IsNotExist() 判斷為 true,說明文件或文件夾不存在;
- 如果返回的錯誤為其他類型,則不確定是否存在。

package main import ( "fmt" "os" ) // 判斷文件或文件夾是否存在 func PathExist(path string) (bool, error) { _, err := os.Stat(path) if err == nil { return true, nil } if os.IsNotExist(err) { return false, nil } return false, err } func main() { filePath := "e:/a.txt" flag, err := PathExist(filePath) if err != nil { fmt.Println(err) } fmt.Println(flag) // true }
五、拷貝文件(帶緩沖方式)
使用 io/Copy 函數:
func Copy(dst Writer, src Reader) (written int64, err error)
將src的數據拷貝到dst,直到在src上到達EOF或發生錯誤。返回拷貝的字節數和遇到的第一個錯誤。
對成功的調用,返回值err為nil而非EOF,因為Copy定義為從src讀取直到EOF,它不會將讀取到EOF視為應報告的錯誤。如果src實現了WriterTo接口,本函數會調用src.WriteTo(dst)進行拷貝;否則如果dst實現了ReaderFrom接口,本函數會調用dst.ReadFrom(src)進行拷貝。

package main import ( "bufio" "fmt" "io" "os" ) // 將 srcFilePath 拷貝到 dstFilePath func CopyFile(dstFilePath string, srcFilePath string) (written int64, err error) { // 打開srcFilePath srcFile, err := os.Open(srcFilePath) if err != nil { fmt.Printf("打開文件出錯:%s\n", err) return } defer srcFile.Close() // 通過 bufio/NewReader,傳入 srcFile,獲取到 reader reader := bufio.NewReader(srcFile) // 打開dstFilePath dstFile, err := os.OpenFile(dstFilePath, os.O_WRONLY | os.O_CREATE, 0666) if err != nil { fmt.Printf("打開文件出錯:%s\n", err) return } defer dstFile.Close() // 通過 bufio/NewWriter,傳入 dstFile,獲取到 writer writer := bufio.NewWriter(dstFile) return io.Copy(writer, reader) } func main() { srcFilePath := "e:/a.mp4" dstFilePath := "f:/b.mp4" _, err := CopyFile(dstFilePath, srcFilePath) if err != nil { fmt.Printf("拷貝文件出錯:%s", err) } fmt.Println("拷貝文件完成") }
六、遍歷一個目錄

package main import ( "fmt" "os" ) func main() { fmt.Println("請輸入一個目錄的路徑:") var path string _, _ = fmt.Scan(&path) // 打開目錄 f, err := os.OpenFile(path, os.O_RDONLY, os.ModeDir) if err != nil { fmt.Printf("Open file failed:%s.\n", err) return } defer f.Close() // 讀取目錄 info, err := f.Readdir(-1) // -1 表示讀取目錄中所有目錄項 // 遍歷返回的切片 for _, fileInfo := range info { if fileInfo.IsDir() { fmt.Printf("%s是一個目錄\n", fileInfo.Name()) } else { fmt.Printf("%s是一個文件\n", fileInfo.Name()) } } }
七、其他
統計一個文件中含有的英文、數字、空格以及其他字符數量。

package main import ( "bufio" "fmt" "io" "os" ) // 定義一個結構體,用於保存統計結果 type CharCount struct { AlphaCount int // 記錄英文個數 NumCount int // 記錄數字的個數 SpaceCount int // 記錄空格的個數 OtherCount int // 記錄其它字符的個數 } func main() { // 思路: 打開一個文件, 創一個 reader // 每讀取一行,就去統計該行有多少個 英文、數字、空格和其他字符 // 然后將結果保存到一個結構體 filePath := "e:/a.txt" file, err := os.Open(filePath) if err != nil { fmt.Printf("打開文件出錯:%s\n", err) return } defer file.Close() // 定義一個 CharCount 實例 var count CharCount //創建一個Reader reader := bufio.NewReader(file) // 開始循環的讀取文件的內容 for { line, err := reader.ReadString('\n') if err == io.EOF { // 讀到文件末尾就退出 break } // 遍歷每一行(line),進行統計 for _, v := range line { switch { case v >= 'a' && v <= 'z': fallthrough // 穿透 case v >= 'A' && v <= 'Z': count.AlphaCount++ case v >= '0' && v <= '9': count.NumCount++ case v == ' ' || v == '\t': count.SpaceCount++ default : count.OtherCount++ } } } // 輸出統計的結果看看是否正確 fmt.Printf("字符的個數為:%v\n數字的個數為:%v\n空格的個數為:%v\n其它字符個數:%v\n", count.AlphaCount, count.NumCount, count.SpaceCount, count.OtherCount) }