基本介紹
文件是數據源,數據庫也是一種特殊的文件。
Go語言中os.File結構體封裝了文件的相關操作。
打開和關閉文件
-----打開文件-----
file, err := os.Open("D:/111.txt")
if err != nil{fmt.Println("err = ", err)
}此時file就是一個指針,不包括實際的file對象內容-----關閉文件-----
err = file.Close()
if err != nil{fmt.Println("Close err = ", err)
}
讀取文件
第一種方式
適用于文件比較大的情況,帶緩沖的讀取文件。
使用bufio包。
-----打開文件-----
file, err := os.Open("D:/111.txt")
if err != nil{fmt.Println("err = ", err)
}
-----關閉文件-----
defer file.Close()
使用defer關閉file句柄,defer在函數最后執行-----讀取文件-----
創建一個*reader 帶緩沖的(內存和硬盤之間存在緩沖區,先放一塊數據到緩沖區)
reader := bufio.NewReader(file)
循環讀取文件內容
for{str, err := reader.ReadString("\n") //讀到一個換行就結束,str中包括換行if err == io.EOF{ io.EOF代表文件結束break }fmt.Print(str)
}
fmt.Println("文件讀取完成")
第二種方式
整個文件直接讀入內存。適用于文件比較小的情況。
使用ioutil包。ioutil包目前已經被棄用。
package main
import("fmt""io/ioutil"
)func main(){file := "d:/test.txt"content, err := ioutil.ReadFile(file)if err != nil{fmt.Println("err = ", err)}fmt.Println(content)content是一個byte切片,因此需要轉一下格式fmt.Println(string(content))
}
該方式不需要顯式讀取和關閉文件。
文件寫入
?bufio包中的Reader和Writer都是有緩沖的讀寫數據。
創建文件并進行寫入
創建和讀取文件使用os包,寫入文件使用bufio包。
使用os.Openfile函數進行文件創建。
第一個參數是文件名。
第二個參數是包含以下選項。
第三個參數在linux系統下,win系統下無效,該參數是進行權限控制的。
package mainimport ("bufio""fmt""os"
)func main() {filePath := "d:/abc.txt"file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0666)if err != nil {fmt.Println("err = ", err)return}// 關閉文件句柄defer file.Close()writer := bufio.NewWriter(file)for i := 0; i < 5; i++ {writer.WriteString("hello,World!\n")}// WriterString帶緩存區的寫入// 因此需要writer.Flush()清空緩沖區,將內存寫入硬盤writer.Flush()}
打開存在的文件并進行內容覆蓋
file, err := os.OpenFile(filePath, os.O_TRUNC|os.O_WRONLY, 0666)
OpenFile函數中的第二個參數os.O_TRUNC代表追加;os.O_WRONLY代表寫入。
打開存在文件進行文件追加
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0666)
os.O_APPEND代表追加。?
打開存在文件將內容顯示在終端,然后進行文件追加
初始化文件使用os包,讀取文件內容使用bufio包,寫入文件使用bufio包,
package mainimport ("bufio""fmt""io""os"
)func main() {filePath := "d:/abc.txt"file, err := os.OpenFile(filePath, os.O_APPEND|os.O_RDWR, 0666)if err != nil {fmt.Println("err = ", err)return}// 關閉文件句柄defer file.Close()// 讀取原來的文件內容,并輸出在終端reader := bufio.NewReader(file)for {str, err := reader.ReadString('\n')if err == io.EOF {break}fmt.Print(str)}// 追加寫入writer := bufio.NewWriter(file)for i := 0; i < 5; i++ {writer.WriteString("11111\r\n")}// WriterString帶緩存區的寫入// 因此需要writer.Flush()清空緩沖區,將內存寫入硬盤writer.Flush()}
將一個文件內容copy到另一個文件之中
讀取文件、寫入文件都使用os包。
package mainimport ("fmt""os"
)func main() {file1Path := "d:/abc.txt"file2Path := "e:/111.txt"// 讀取源文件內容data, err := os.ReadFile(file1Path)if err != nil {fmt.Println("讀取文件失敗:", err)return}// 將內容寫入目標文件err = os.WriteFile(file2Path, data, 0644)if err != nil {fmt.Println("寫入文件失敗:", err)return}fmt.Println("文件復制成功")
}
拋開錯誤處理,就兩步,一個讀,一個寫。
判斷文件是否存在
- 使用os.Star()函數判斷是否存在。
import ("os""fmt"
)func checkExist(path string) {fileInfo, err := os.Stat(path)if err != nil {if os.IsNotExist(err) {fmt.Printf("路徑 %q 不存在\n", path)} else {fmt.Printf("發生錯誤: %v\n", err)}return}if fileInfo.IsDir() {fmt.Printf("%q 是一個目錄\n", path)} else {fmt.Printf("%q 是一個文件\n", path)}
}
os.Star(Path)?返回值:
- 如果成功:返回一個os.FileInfo接口,包含文件/目錄的信息。
- 如果失敗:返回一個非 nil 的 error。
判斷是否存在的標準方式
if os.IsNotExist(err) {// 路徑不存在
} else if err != nil {// 其他錯誤,比如權限不足
}
不能直接使用err == 進行判斷,就使用os.IsNotExist()進行判斷
?后續使用中一般都是封裝成函數進行使用。
文件操作編程實例
1. 編寫一個函數,將一個圖片拷貝到另一個文件夾中。
func CopyFile(src, dst string) {// 打開源文件srcFile, _ := os.Open(src)defer srcFile.Close()// 創建目標目錄(如果不存在)os.MkdirAll(filepath.Dir(dst), 0755)// 創建目標文件dstFile, _ := os.Create(dst)defer dstFile.Close()// 拷貝內容io.Copy(dstFile, srcFile)
}
在這個例子中,srcFile和dstFiled都是*os.File類型
?io.Copy()接受Writer和Reader接口類型,也就是說*os.File類型實現了io.Reader和io.Writer。直接使用沒有問題。
2. 統計一個文件中含有多少英文、數字等信息
package mainimport ("bufio""fmt""io""os"
)type CharCount struct {ChCount int // 記錄英文個數NumCount int // 記錄數字的個數SpaceCount int // 記錄空格的個數OtherCount int // 記錄其他字符的個數
}func main() {filePath := "d:/abc.txt"file, err := os.Open(filePath)if err != nil {fmt.Println(err)return}defer file.Close()var count CharCount// 使用帶緩沖的讀取// bufio包中是帶緩沖的讀取,讀取之前必須先拿到文件的句柄// os.ReadFile()函數不帶緩沖讀,不需要打開文件句柄,直接放入文件路徑即可reader := bufio.NewReader(file)for {str, err := reader.ReadString('\n')if err == io.EOF {break}for _, v := range str {switch {case v >= 'a' && v <= 'z':fallthrough //穿透處理,直接進入到下一個casecase v >= 'A' && v <= 'Z':count.ChCount++case v == ' ' || v == '\t':count.SpaceCount++case v >= '0' && v <= '9':count.NumCount++default:count.OtherCount++}}}fmt.Println(count)
}