在Go語言中,文件是使用一個os.File類的對象指針表示的,也能夠稱這指針爲文件句柄(filehandle),os.Stdin和os.Stdout也是屬於這個*os.File類型的。web
下面舉例說明windows
package main
import (
"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 循環便結束了。數組
這裏還有一些可代替的方法app
一、能夠以字符串(字節串)方式一次性讀一個完整文件的內容,io/ioutil包裏的ioutil.ReadFile() 實現這個功能,它返回一個它所讀到的字節的[]byte 數組及nil,或者其它錯誤,相似地ioutil.WriteFile則將一個[]byte 寫到一個文件裏去。函數
兩個函數的原型spa
func ReadFile(filename string) ([]byte, error)
命令行
func WriteFile(filename string, data []byte, perm os.FileMode) error
unix
package main
import (
"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())
}
}
二、帶緩衝的讀文件,除了使用ReadString(),一些狀況下咱們並非一行行地讀文件或二進行文件,咱們能夠用bufio.Reader的Read()方法,方式以下指針
buf := make([]byte,1024) //code
...
n,err := inputReader.Read(buf)
if(n==0){break} //n爲實際所讀到的byte數,當文件的字節數少於緩衝數組的長度時,會返回實際的字節數,
package main
import (
"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 []stringfor {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)