Go语言下的文件读写操作

学思 · · 5989 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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

有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:学思

查看原文:Go语言下的文件读写操作

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

5989 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传