1. 程式人生 > 實用技巧 >go 檔案操作實踐

go 檔案操作實踐

go常用操作檔案有json,xml, gob 和txt,一般json,xml, gob 都是全部操作 很少修改一個部分快的內容, 所以一般採用 編碼、解碼實現,txt可能有追加所以相對難一點。 說說自己遇到的坑

1.驗證檔案或者目錄是否存在

// 檢查檔案或目錄是否存在
// 如果由 filename 指定的檔案或目錄存在則返回 true,否則返回 false
func IsExist(filename string) bool {
    _, err := os.Stat(filename)
    return err == nil || os.IsExist(err)
}

2在讀取文字檔案的時候

Readline讀滿緩衝區就返回,剩下的位元組不會丟棄,留著下次讀取。這樣一行就拆分成了兩次讀取,兩次讀取出來的行都與預期的不符,後續的邏輯流程肯定也異常了
解決方法:
1.直接換成ReadBytes(’\ n’) 或 ReadString(’\ n’)
2.對isPrefix返回值做校驗

3.os.OpenFile(filePath,os.O_RDWR|os.O_APPEND,0666) 這個方法的flag一定要注意, 比如 設定成os.O_WRONLY|os.O_APPEND , 去讀取檔案, 結果是阻塞不是報錯。

整個dmeo 如下:

package main
 
import (
    
"bufio" "encoding/gob" "encoding/json" "encoding/xml" "fmt" "io" "os" ) type Website struct { Name string `xml:"name,attr"` Url string Course []string } var info []Website func init() { info = []Website{ {"Golang", "http://c.biancheng.net/golang/", []string
{"http://c.biancheng.net/cplus/", "http://c.biancheng.net/linux_tutorial/"}}, {"Java", "http://c.biancheng.net/java/", []string{"http://c.biancheng.net/socket/", "http://c.biancheng.net/python/"}}, } /* 列舉了一些常用的 flag 檔案處理引數: O_RDONLY:只讀模式開啟檔案; O_WRONLY:只寫模式開啟檔案; O_RDWR:讀寫模式開啟檔案; O_APPEND:寫操作時將資料附加到檔案尾部(追加); O_CREATE:如果不存在將建立一個新檔案; O_EXCL:和 O_CREATE 配合使用,檔案必須不存在,否則返回一個錯誤; O_SYNC:當進行一系列寫操作時,每次都要等待上次的 I/O 操作完成再進行; O_TRUNC:如果可能,在開啟時清空檔案。 */ } // 檢查檔案或目錄是否存在 // 如果由 filename 指定的檔案或目錄存在則返回 true,否則返回 false func IsExist(filename string) bool { _, err := os.Stat(filename) return err == nil || os.IsExist(err) } func main() { WriteJson() ReadJson() WriteXml() ReadXML() WriteGob() ReadGob() WriteorCreatetxt() OpenAndAppendtxt() txtReadLine() } func WriteJson() { path := "./info.json" if IsExist(path) { os.Remove(path) } fileptr, err := os.Create(path) if err != nil { fmt.Printf("crete json file has error:%v\n", err) return } defer fileptr.Close() encoder := json.NewEncoder(fileptr) err = encoder.Encode(info) if err != nil { fmt.Printf("json encode hase error %v\n", err) } else { fmt.Println("json write done") } } func ReadJson() { path := "./info.json" fileptr, err := os.Open(path) if err != nil { fmt.Printf("open json file has error:%v\n", err) return } defer fileptr.Close() var tmp []Website decoder := json.NewDecoder(fileptr) err = decoder.Decode(&tmp) if err != nil { fmt.Printf("json decode has error:%v\n", err) } fmt.Println("json read done") fmt.Print(tmp) } func WriteXml() { path := "./info.xml" if IsExist(path) { os.Remove(path) } fileptr, err := os.Create(path) if err != nil { fmt.Printf("crete xml file has error:%v\n", err) return } defer fileptr.Close() encoder := xml.NewEncoder(fileptr) err = encoder.Encode(info) if err != nil { fmt.Printf("xml encode hase error %v\n", err) } else { fmt.Println("xml write done") } } func ReadXML() { path := "./info.xml" fileptr, err := os.Open(path) if err != nil { fmt.Printf("open xml file has error:%v\n", err) return } defer fileptr.Close() var tmp []Website decoder := xml.NewDecoder(fileptr) err = decoder.Decode(&tmp) if err != nil { fmt.Printf("xml decode has error:%v\n", err) } fmt.Println("xml read done") fmt.Print(tmp) } func WriteGob() { path := "./demo.gob" if IsExist(path) { os.Remove(path) } file, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0777) defer file.Close() enc := gob.NewEncoder(file) if err := enc.Encode(info); err != nil { fmt.Printf("gob endcod has err:%v", err) } else { fmt.Println("gob write don") } } func ReadGob() { path := "./demo.gob" fileptr, err := os.Open(path) if err != nil { fmt.Printf("open gob file has error:%v\n", err) return } defer fileptr.Close() var tmp []Website decoder := gob.NewDecoder(fileptr) err = decoder.Decode(&tmp) if err != nil { fmt.Printf("gob decode has error:%v\n", err) } fmt.Println("gob read done") fmt.Print(tmp) } func WriteorCreatetxt() { filePath := "./info.txt" file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { fmt.Printf("txt open file has err:%v", err) } defer file.Close() //寫入檔案時,使用帶快取的 *Writer write := bufio.NewWriter(file) for i := 0; i < 5; i++ { write.WriteString(fmt.Sprintf("hello:%d \r\n", i+1)) } //Flush將快取的檔案真正寫入到檔案中 write.Flush() fmt.Println("txt write done") } func OpenAndAppendtxt() { filePath := "./info.txt" file, err := os.OpenFile(filePath, os.O_RDWR|os.O_APPEND, 0666) if err != nil { fmt.Printf("txt open file has err:%v", err) } defer file.Close() //讀原來檔案的內容,並且顯示在終端 reader := bufio.NewReader(file) for { str, err := reader.ReadString('\n') if err == io.EOF { break } fmt.Print(str) } //寫入檔案時,使用帶快取的 *Writer write := bufio.NewWriter(file) for i := 0; i < 5; i++ { write.WriteString(fmt.Sprintf("world %d\r\n", i+1)) } //Flush將快取的檔案真正寫入到檔案中 write.Flush() fmt.Println("txt append done") } /* Readline讀滿緩衝區就返回,剩下的位元組不會丟棄,留著下次讀取。 這樣一行就拆分成了兩次讀取,兩次讀取出來的行都與預期的不符,後續的邏輯流程肯定也異常了 解決方法: 1.直接換成ReadBytes(’\ n’) 或 ReadString(’\ n’) 2.對isPrefix返回值做校驗 */ func txtReadLine() { // 開啟test.txt檔案 fi, err := os.Open("./test.txt") if err != nil { fmt.Println("open file error:", err) return } defer fi.Close() // 逐行讀取記錄 br := bufio.NewReader(fi) var buf []byte for { line, prefix, err := br.ReadLine() if err == io.EOF { break } // 追加到自定義緩衝區內 buf = append(buf, line...) // 如果prefix為真,則代表該行還有尚未讀取完的資料,跳過後續具體操作,繼續讀取完該行剩餘內容 if prefix { continue } str := string(buf) fmt.Printf("--------------------\n") fmt.Println("len(buf) = ", len(buf)) fmt.Println("len(str) = ", len(str)) fmt.Println(str) fmt.Printf("--------------------\n\n") // 清空切片 buf = append(buf[:0], buf[len(buf):]...) } fmt.Println("txt readline done") }