Go语言下的文件读写操作

在Go语言中,文件是使用一个os.File类的对象指针表示的,也可以称这指针为文件句柄(filehandle),os.Stdin和os.Stdout也是属于这个*os.File类型的。

下面举例说明

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 循环便结束了。


这里还有一些可代替的方法

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

    }


}

2、带缓冲的读文件,除了使用ReadString(),一些情况下我们并不是一行行地读文件或二进行文件,我们可以用bufio.Reader的Read()方法,方式如下

buf := make([]byte,1024)   //

...

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 main

import (
    "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)



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。