這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
在Go語言中,檔案是使用一個os.File類的對象指標表示的,也可以稱這指標為檔案控制代碼(filehandle),os.Stdin和os.Stdout也是屬於這個*os.File類型的。
下面舉例說明
package mainimport ( "bufio" "fmt" "io" "os")func main() { inputFile, inputError := os.Open(os.Args[1])//變數指向os.Open開啟的檔案時產生的檔案控制代碼 if inputError != nil { fmt.Printf("An error occurred on opening the inputfile\n") return } defer inputFile.Close() inputReader := bufio.NewReader(inputFile) lineCounter := 0 for { inputString, readerError := inputReader.ReadString('\n') //inputString, readerError := inputReader.ReadBytes('\n') if readerError == io.EOF { return } lineCounter++ fmt.Printf("%d : %s", lineCounter, inputString) }}
上例中的的inputFile是一個os.File的類型變數,它指向一個開啟的檔案描述符(檔案控制代碼)。os.Open函數接受一個檔案名稱作為參數,上例中使用的是os.Args[1]的命令列裡的第一個參數,os.Args[0]指程式本身。 使用os.Open開啟的檔案為唯讀模式,另外一個函數OpenFile(name string, flag int, perm FileMode) (file File, err error) 指代更多的操作模式。當要開啟的檔案不存在或程式沒有足夠許可權時,會報錯。defer.Close()函數的作用是為了保證程式結束前,這個被開啟的檔案能為關閉。關鍵字defer具有順延強制功能。通過bufio.NewReader(inputFile),我們獲得一個帶緩衝的reader。之所以轉換為使用bufio包裡的reader(或者writer),是因為這樣我們就可以使用一些實用的進階別的字串對象,而不是底層原始的bytes資料。接著,使用ReadString('\n')或者ReadBytes('\n')方法無限迴圈一行行地讀檔案內容,值得注意的是,無論是unix系統還是windows系統,ReadString、ReadBytes還有ReadLine都能通過'\n'識別為換行。當我們讀取檔案直到檔案結束時,readerError !=nil (readerError==io.EOF),這個for 迴圈便結束了。
這裡還有一些可代替的方法
1、可以以字串(位元組串)方式一次性讀一個完整檔案的內容,io/ioutil包裡的ioutil.ReadFile() 實現這個功能,它返回一個它所讀到的位元組的[]byte 數組及nil,或者其它錯誤,類似地ioutil.WriteFile則將一個[]byte 寫到一個檔案裡去。
兩個函數的原型
func ReadFile(filename string) ([]byte, error) func WriteFile(filename string, data []byte, perm os.FileMode) error
樣本:
package mainimport ( "fmt" "io/ioutil" "os")func main() { inputFile := os.Args[1] outputFile := os.Args[2] buf, err := ioutil.ReadFile(inputFile) if err != nil { fmt.Fprintf(os.Stderr, "File Error: %s\n", err) } fmt.Printf("%s\n", string(buf)) err = ioutil.WriteFile(outputFile, buf, 0x644) if err != nil { panic(err.Error()) }}
2、帶緩衝的讀檔案,除了使用ReadString(),一些情況下我們並不是一行行地讀檔案或二進行檔案,我們可以用bufio.Reader的Read()方法,方式如下
buf := make([]byte,1024) //...n,err := inputReader.Read(buf)if(n==0){break} //n為實際所讀到的byte數,當檔案的位元組數少於緩衝數組的長度時,會返回實際的位元組數,
樣本:
package mainimport ( "fmt" //"io/ioutil" "bufio" "os")func main() { inputFile, inputError := os.Open(os.Args[1]) if inputError != nil { fmt.Fprintf(os.Stderr, "File Error: %s\n", inputError) } fileReader := bufio.NewReader(inputFile) counter := 0 for { buf := make([]byte, 1024) n, _ := fileReader.Read(buf) counter++ //fmt.Printf("%d,%s", n, string(buf)) if n == 0 { break } //fmt.Println(n, buf) fmt.Printf("%d,%s", n, string(buf)) fmt.Printf("/////////////////\n") } fmt.Println(counter)}
3 、從檔案中讀列資料。如果檔案是以空格分隔的列資料,則可以使用fmt包裡的Fscan系列函數,下面的例子使用了這種方式,它將從列中的讀到的資料賦值到變數v1,v2和V3,然後追加到一個數組切片去。
package mainimport ( "fmt" "os")func main() { file, err := os.Open(os.Args[1]) if err != nil { panic(err) } var col1, col2, col3 []string for { var v1, v2, v3 string _, err := fmt.Fscanln(file, &v1, &v2, &v3)//Fscanln 將一次唯讀一行,並將每列的資料賦值給相應的變數 if err != nil { break } col1 = append(col1, v1) col2 = append(col2, v2) col3 = append(col3, v3) } fmt.Println(col1) fmt.Println(col2) fmt.Println(col3)}
要讀的檔案內容為
a1 a2 a3
b1 b2 b3
c1 c2 c3
輸出為
[a1 b1 c1]
[a2 b2 c2]
[a3 b3 c3]
備忘: path包下有個子包filepath,它提供了些跨平台的處理檔案路徑及檔案名稱的函數,例如filepath.Base(path)返迴文件路徑的最後一個元素。
import "path/filepath"filename := filepath.Base(path)