Golang的文本文件處理-文件操作常見的API
作者:尹正傑
版權聲明:原創作品,謝絕轉載!否則將追究法律責任。
一.打開文件相關操作
1>.如果文件不存在就創建文件,如果文件存在就清空文件內容並打開(Create方法)
package main import ( "errors" "fmt" "os" ) func main() { /** 創建文件的API函數簽名如下所示: func Create(name string) (*File, error) 下面是對API的參數解釋說明: name: 指的是文件名稱,可以是相對路徑,也可以是絕對路徑。 *File: 指的是文件指針,我們使用完文件后要記得釋放該文件指針資源 error: 指的是創建文件的報錯信息,比如指定的文件父目錄不存在就會報錯"The system cannot find the path specified." 溫馨提示: 根據提供的文件名創建新的文件,返回一個文件對象,返回的文件對象是可讀寫的。 創建文件時,如果存在重名的文件就會覆蓋掉原來的文件。換句話說,如果文件存在就清空文件內容並打開新文件,如果文件不存在則創建新文件並打開。 */ f, err := os.Create("E:\\yinzhengjie\\input\\kafka.txt") /** 一旦文件報錯就執行return語句,下面的defer語句就不會被執行到喲~ 溫馨提示: 我們不要將下面的defer語句和判斷錯誤的語句互換位置,因為判斷錯誤的語句是來確保文件是否創建成功; 如果有錯誤意味着文件沒有被成功創建,換句話說,如果文件創建失敗,那么文件指針為空,此時如果執行關閉文件會報錯喲; 如果沒有錯誤就意味着文件創建成功,即在執行關閉文件的操作是確保不會報錯 */ if err != nil { fmt.Println(errors.New("報錯提示:" + err.Error())) return } else { fmt.Println("文件創建成功....") } /** 文件成功創建之后,一直處於打開狀態,因此我們使用完之后一定要關閉文件,當然關閉文件之前一定要確保為文件已經創建成功。 */ defer f.Close() }

2>.以只讀方式打開文件(Open方法)
package main import ( "errors" "fmt" "os" ) func main() { /** 打開文件的API函數實現如下所示,很明顯它是基於OpenFile實現的 func Open(name string) (*File, error) { return OpenFile(name, O_RDONLY, 0) } 下面是對API的參數解釋說明: name: 指的是文件名稱,可以是相對路徑,也可以是絕對路徑。 *File: 指的是文件指針,我們使用完文件后要記得釋放該文件指針資源 error: 指的是創建文件的報錯信息,比如指定的文件不存在就會報錯"The system cannot find the file specified." 溫馨提示: Open()是以只讀權限打開文件名為name的文件,得到的文件指針file,只能用來對文件進行"讀"操作。 如果我們有"寫"文件的需求,就需要借助"Openfile"函數來打開了。 */ f, err := os.Open("E:\\yinzhengjie\\input\\kafka.txt") /** 一旦文件報錯就執行return語句,下面的defer語句就不會被執行到喲~ 溫馨提示: 我們不要將下面的defer語句和判斷錯誤的語句互換位置,因為判斷錯誤的語句是來確保文件是否創建成功; 如果有錯誤意味着文件沒有被成功創建,換句話說,如果文件創建失敗,那么文件指針為空,此時如果執行關閉文件會報錯喲; 如果沒有錯誤就意味着文件創建成功,即在執行關閉文件的操作是確保不會報錯 */ if err != nil { fmt.Println(errors.New("報錯提示:" + err.Error())) return } else { fmt.Println("文件打開成功....") } /** 文件成功創建之后,一直處於打開狀態,因此我們使用完之后一定要關閉文件,當然關閉文件之前一定要確保為文件已經創建成功。 */ defer f.Close() }

3>.自定義文件的打開方式(OpenFile方法)
package main import ( "errors" "fmt" "os" ) func main() { /** 創建文件的API函數簽名如下所示: func OpenFile(name string, flag int, perm FileMode) (*File, error) 下面是對API的參數解釋說明: name: 指的是文件名稱,可以是相對路徑,也可以是絕對路徑。 flag: 表示讀寫模式,常見的模式有:O_RDONLY(只讀模式), O_WRONLY(只寫模式), O_RDWR(可讀可寫模式)。 perm: 表示打開權限。來源於Linux系統調用中的open函數,參2為:O_CREATE時,可創建新文件。 權限取值范圍是八進制,即"0-7".表示如下: 0:沒有任何權限 1:執行權限(如果是可執行文件,是可以運行的) 2:寫權限 3: 寫權限與執行權限 4:讀權限 5: 讀權限與執行權限 6: 讀權限與寫權限 7: 讀權限,寫權限,執行權限 *File: 指的是文件指針,我們使用完文件后要記得釋放該文件指針資源 error: 指的是創建文件的報錯信息,比如指定的文件父目錄不存在就會報錯"The system cannot find the path specified." 溫馨提示: 使用OpenFile打開的文件,默認寫的時候是聰文件開頭開始寫入數據,這樣會將原來的數據覆蓋掉; 如果不想覆蓋的方式寫入,使用追加的方式寫入,具體代碼如下所示(當然你也可以使用Seek函數實現喲~)。 */ f, err := os.OpenFile("E:\\yinzhengjie\\input\\kafka.txt", os.O_RDWR|os.O_APPEND, 0666) /** 一旦文件報錯就執行return語句,下面的defer語句就不會被執行到喲~ 溫馨提示: 我們不要將下面的defer語句和判斷錯誤的語句互換位置,因為判斷錯誤的語句是來確保文件是否創建成功; 如果有錯誤意味着文件沒有被成功創建,換句話說,如果文件創建失敗,那么文件指針為空,此時如果執行關閉文件會報錯喲; 如果沒有錯誤就意味着文件創建成功,即在執行關閉文件的操作是確保不會報錯 */ if err != nil { fmt.Println(errors.New("報錯提示:" + err.Error())) return } else { fmt.Println("文件創建成功....") } /** 文件成功創建之后,一直處於打開狀態,因此我們使用完之后一定要關閉文件,當然關閉文件之前一定要確保為文件已經創建成功。 */ defer f.Close() }
二.寫文件相關操作
1>.Write方法
package main import ( "errors" "fmt" "os" ) func main() { f, err := os.Create("E:\\yinzhengjie\\input\\kafka.txt") if err != nil { fmt.Println(errors.New("報錯提示:" + err.Error())) return } else { fmt.Println("文件創建成功....") } /** 文件成功創建之后,一直處於打開狀態,因此我們使用完之后一定要關閉文件,當然關閉文件之前一定要確保為文件已經創建成功。 */ defer f.Close() /** 寫入字節切片到文件中,Write的函數簽名如下所示: func (f *File) Write(b []byte) (n int, err error) 如上所示,我們只需要傳入需要寫入的字節切片即可將內容寫到操作系統中對應的文件。 */ f.Write([]byte("Kafka是一個吞吐量高的消息隊列\n")) }
2>.WriteString方法
package main import ( "errors" "fmt" "os" ) func main() { f, err := os.Create("E:\\yinzhengjie\\input\\kafka.txt") if err != nil { fmt.Println(errors.New("報錯提示:" + err.Error())) return } else { fmt.Println("文件創建成功....") } /** 文件成功創建之后,一直處於打開狀態,因此我們使用完之后一定要關閉文件,當然關閉文件之前一定要確保為文件已經創建成功。 */ defer f.Close() /** 寫入字符串到文件,其函數實現如下,很明顯,WriteString底層調用的依舊是Write方法。 func (f *File) WriteString(s string) (n int, err error) { return f.Write([]byte(s)) } 如上所示,我們只需要傳入需要寫入的字符串即可將內容寫到操作系統中對應的文件。 */ f.WriteString("Kafka是一個消息隊列") }
3>.WriteAt方法
package main import ( "errors" "fmt" "os" ) func main() { f, err := os.Create("E:\\yinzhengjie\\input\\kafka.txt") if err != nil { fmt.Println(errors.New("報錯提示:" + err.Error())) return } else { fmt.Println("文件創建成功....") } /** 文件成功創建之后,一直處於打開狀態,因此我們使用完之后一定要關閉文件,當然關閉文件之前一定要確保為文件已經創建成功。 */ defer f.Close() /** WriteAt是帶偏移量的寫入數據,偏移量是從文件起始位置開始,WriteAt的函數簽名如下所示: func (f *File) WriteAt(b []byte, off int64) (n int, err error) 以下是對函數簽名相關參數說明: b: 待寫入的數據內容 off: 偏移量(通常是Seek函數返回值) */ f.WriteAt([]byte("Kafka"), 10) }
4>.Seek方法
package main import ( "fmt" "os" "syscall" ) const ( // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified. O_RDONLY int = syscall.O_RDONLY // open the file read-only. O_WRONLY int = syscall.O_WRONLY // open the file write-only. O_RDWR int = syscall.O_RDWR // open the file read-write. // The remaining values may be or'ed in to control behavior. O_APPEND int = syscall.O_APPEND // append data to the file when writing. O_CREATE int = syscall.O_CREAT // create a new file if none exists. O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist. O_SYNC int = syscall.O_SYNC // open for synchronous I/O. O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened. ) func main() { f, err := os.OpenFile("E:\\yinzhengjie\\input\\flume.txt", O_RDWR|O_CREATE|O_TRUNC, 0666) if err != nil { fmt.Println("err = ", err) return } defer f.Close() f.Write([]byte("Flume 是一個文本日志收集工具。\n")) f.WriteString("Flume是一種分布式,可靠且可用的服務,用於有效地收集,聚合和移動大量日志數據。") f.WriteAt([]byte("Flume具有基於流數據流的簡單靈活的體系結構。"), 60) //可以指定偏移量寫入 /** Seek的函數簽名如下所示: func (f *File) Seek(offset int64, whence int) (ret int64, err error) 以下是對函數簽名相關參數說明: offset: 指定偏移量,如果是正數,則表示向文件尾偏;如果是負數,則表示向文件頭偏. whence: 指定偏移量的起始位置. io.SeekStart: 文件起始位置,對應常量整型0. io.SeekCurrent: 文件當前位置,對應常量整型1. io.SeekEnd: 文件結尾位置,對應常量整型2. 返回值: 表示從文件起始位置,到當前文件讀寫指針位置的偏移量。 */ f.Seek(10, 2) f.WriteString("Flume具有可調整的可靠性機制以及許多故障轉移和恢復機制,具有強大的功能和容錯能力。") }
三.讀文件相關操作
Flume是一種分布式,可靠且可用的服務,用於有效地收集,聚合和移動大量日志數據。
它具有基於流數據流的簡單靈活的體系結構。
它具有可調整的可靠性機制以及許多故障轉移和恢復機制,具有強大的功能和容錯能力。
它使用一個簡單的可擴展數據模型,允許在線分析應用程序。
1>.Read方法
package main import ( "fmt" "os" ) func main() { f, err := os.OpenFile("E:\\yinzhengjie\\input\\flume.txt", os.O_RDWR|os.O_APPEND, 0666) if err != nil { fmt.Println("文件打開失敗: ", err) return } defer f.Close() /** 切片在使用前要申請內存空間,如果不知道文件的大小,盡量多給點空間最好是4K的倍數 如果在讀取大文件的情況下,我們應該循環讀取,當然,我的筆記里有讀取大文件的實戰案例。 */ temp := make([]byte, 1024*4) f.Read(temp) fmt.Println(string(temp)) }

2>.ReadAt方法
package main import ( "fmt" "os" ) func main() { f, err := os.OpenFile("E:\\yinzhengjie\\input\\flume.txt", os.O_RDWR|os.O_APPEND, 0666) if err != nil { fmt.Println("文件打開失敗: ", err) return } defer f.Close() temp := make([]byte, 1024*4) f.ReadAt(temp, 5) //帶偏移量的獲取數據,是從文件頭開始的,當然我們使用Seek函數也能實現該功能 fmt.Println(string(temp)) }

3>.按行讀取案例
package main import ( "bufio" "bytes" "fmt" "os" ) func main() { f, err := os.OpenFile("E:\\yinzhengjie\\input\\flume.txt", os.O_RDWR|os.O_APPEND, 0666) if err != nil { fmt.Println("文件打開失敗: ", err) return } defer f.Close() buf := make([]byte, 1024*4) f.Read(buf) //一定要將數據讀到切片中,否則執行下面的操作會讀取不到數據喲~ reader := bufio.NewReader(bytes.NewReader(buf)) //初始化一個閱讀器 line, _ := reader.ReadString('\n') //為閱讀器指定分隔符為換行符("\n"),即每次只讀取一行. fmt.Println(line) }

四.刪除文件
package main import ( "os" ) func main() { os.Remove("E:\\yinzhengjie\\input\\kafka.txt") //刪除文件 }
五.大文件拷貝案例
package main import ( "fmt" "io" "os" ) func main() { args := os.Args //獲取命令行參數, 並判斷輸入是否合法 if args == nil || len(args) != 3 { fmt.Println("useage : xxx srcFile dstFile") return } srcPath := args[1] //獲取源文件路徑 dstPath := args[2] //獲取目標文件路徑 fmt.Printf("srcPath = %s, dstPath = %s\n", srcPath, dstPath) if srcPath == dstPath { fmt.Println("error:源文件名與目的文件名相同") return } srcFile, err1 := os.Open(srcPath) // 打開源文件 if err1 != nil { fmt.Println(err1) return } dstFile, err2 := os.Create(dstPath) //創建目標文件 if err2 != nil { fmt.Println(err2) return } buf := make([]byte, 1024) //切片緩沖區 for { //從源文件讀取內容,n為讀取文件內容的長度 n, err := srcFile.Read(buf) if err != nil && err != io.EOF { fmt.Println(err) break } if n == 0 { fmt.Println("文件處理完畢") break } //切片截取 tmp := buf[:n] //把讀取的內容寫入到目的文件 dstFile.Write(tmp) } //關閉文件 srcFile.Close() dstFile.Close() }

