在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)