golang读写文件的几种方式

golang中处理文件有不少种方式,下面咱们来看看。python

(1)使用os模块

先来看看如何查看文件属性linux

package main

import (
    "fmt"
    "os"
)

func main() {
    //打开文件使用os.Open函数,会返回一个文件句柄和一个error
    file, err := os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)
    if err != nil {
        fmt.Println("文件打开失败:",err)
    }

    //调用file.Stat()能够查看文件的信息,这是一个os.FileInfo对象
    info, err := file.Stat()
    //属性以下
    /*
    type FileInfo interface {
        Name() string       // 文件名
        Size() int64        // 文件的大小,按字节计算
        Mode() FileMode     // 文件的模式
        ModTime() time.Time // 修改时间
        IsDir() bool        // 是不是目录
        Sys() interface{}   // 数据源,通常不用管
    }
     */
    fmt.Println(info.Name()) // whiteblum.txt
    fmt.Println(info.Size()) // 183

    //有点相似于linux里面的,第一个-表示文本文件,后面的三个rw-表示可读可写不可执行。
    //分别是用户、用户所属组、其余组的权限
    fmt.Println(info.Mode()) // -rw-rw-rw-
    fmt.Println(info.ModTime()) // 2019-08-31 19:52:44.3146692 +0800 CST
    fmt.Println(info.IsDir()) // false
    fmt.Println(info.Sys())  // &{32 {2579124676 30760946} {2579124676 30760946} {2579124676 30760946} 0 183}
}

读取文件里面的内容ios

package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)
    if err != nil {
        fmt.Println("文件打开失败:",err)
    }
    //忘记说了,文件打开是要关闭的,调用defer函数便可
    defer file.Close()

    //此外file.Name()还能够拿到文件的所在路径,file.Fd()则是拿到文件的描述符
    fmt.Println(file.Name()) //D:\komeijisatori\src\day3\whiteblum.txt
    fmt.Println(file.Fd()) // 216

    //读取文件内容能够调用file.Read()方法,接收一个字节数组,返回一个int和error
    buf := make([]byte, 12)
    //此时文件的内容都会读到buf里面,n则是写入了多少个字节,n不会超过字节数组buf的长度
    n, err := file.Read(buf)
    
    //将写入的内容读取出来
    fmt.Println(string(buf[:n])) //白色相簿
}

咱们注意到:当前只是读取了12个字节,并无所有读取完。这是由于咱们的buf长度只有12,咱们能够将容量变得更大一些,可是到底要弄多大呢?这是一个未知数。弄小了一次读不完,要是弄大了,会浪费。所以最好的办法,不要一次就读完,而是循环读取,这样不就行了吗?通常的话,咱们都将buf的长度设置为1024个字节,但因为个人文件比较小,因此就设置为12个字节golang

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    file, err := os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)
    if err != nil {
        fmt.Println("文件打开失败:",err)
    }
    defer file.Close()

    buf := make([]byte, 12) // 存放文件内容的缓存,至关于中转站
    data := make([]byte, 0) // 用来存放文件内容,buf读取的内容都会写到data里面去

    for {
        //无限循环,不断读取
        n, err := file.Read(buf)
        // 何时文件读完呢?若是文件读完的话,那么err不为nil,而是io.EOF
        // 因此咱们能够进行判断
        if err != nil {
            //若是err != nil说明出错了,但若是还等于io.EOF的话,说明读完了,由于文件读完,err也不为nil。直接break
            if err == io.EOF{
                break
            } else {
                //若是错误不是io.EOF的话,说明就真的在读取中出现了错误,直接panic出来
                panic(err)
            }
        }
        //此时文件内容写到buf里面去了,写了多少个呢?写了n个,那么咱们再写到data里面去
        data = append(data, buf[: n]...)

        //咱们来打印一下,每次写了多少个字节
        fmt.Printf("写入%d个字节\n", n)
        /*
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入12个字节
        写入6个字节
         */
    }

    //写完以后,咱们来打印一下
    fmt.Println(string(data))
    /*
    白色相簿什么的,已经无所谓了。
    由于已经再也不有歌,值得去唱了。
    传达不了的恋情,已经不须要了。
    由于已经再也不有人,值得去爱了。
    */
}

那么如何使用os模块来写入文件呢?web

package main

import (
    "fmt"
    "os"
)

func main() {
    //既然要写,那么就不能使用Open了,而是使用Create
    //Create会建立一个文件,若是存在会清空原有的内容
    file, err := os.Create(`D:\komeijisatori\src\day3\whiteblum.txt`)
    if err != nil {
        fmt.Println("文件建立失败:",err)
    }
    defer file.Close()
    //写入文件能够调用file.WriteString,或者file.Write方法
    //前者是写入字符,后者是写入字节。
    // 其实WriteString底层是将咱们传入的字符串变成字节数组,而后仍是调用Write方法
    //会有两个返回值,一个是咱们写入的个数,一个是error
    n, err := file.WriteString("这是新写入的内容,原来的内容会丢失")
    //golang是按照字节算的,一个汉字占三个字节
    fmt.Println(n) // 51

    //再来读取一下看看,有没有写入
    file, err = os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)
    //直接将数组设置的大一些,一次读取完毕
    new_buf := make([]byte, 1024)
    n, _ = file.Read(new_buf)
    fmt.Println(string(new_buf[: n])) // 这是新写入的内容,原来的内容会丢失
}

其实不管是Open仍是Create,底层都是调用了OpenFile数组

package main

import (
    "fmt"
    "os"
)

func main() {
    // OpenFile接收三个参数
    // 1.文件名
    // 2.文件的模式,支持以下
    /*
    os.O_RDONLY: 以只读的方式打开
    os.O_WRONLY: 以只写的方式打开
    os.O_RDWR : 以读写的方式打开
    os.O_NONBLOCK: 打开时不阻塞
    os.O_APPEND: 以追加的方式打开
    os.O_CREAT: 建立并打开一个新文件
    os.O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)
    os.O_EXCL: 若是指定的文件存在,返回错误
    os.O_SHLOCK: 自动获取共享锁
    os.O_EXLOCK: 自动获取独立锁
    os.O_DIRECT: 消除或减小缓存效果
    os.O_FSYNC : 同步写入
    os.O_NOFOLLOW: 不追踪软连接
     */
    // 3.权限,通常设置为0666,这在linux下有用,Windows下面没太大卵用

    // 以只写的方式打开,而且写入的时候,是以追加的形式写入
    file, _ := os.OpenFile(`D:\komeijisatori\src\day3\whiteblum.txt`,os.O_WRONLY|os.O_APPEND, 0666)

    _, _ = file.Write([]byte("\n这是新的内容,可是原来的内容还在"))

    //写入以后,咱们再以只读方式打开
    file, _ = os.OpenFile(`D:\komeijisatori\src\day3\whiteblum.txt`,os.O_RDONLY, 0666)
    buf := make([]byte, 1024)
    n, _ := file.Read(buf)
    fmt.Println(string(buf[: n]))
    /*
    这是新写入的内容,原来的内容会丢失
    这是新的内容,可是原来的内容还在
     */
}

可是一般咱们直接使用Open和Create函数缓存

(2)使用bufio

bufio至关因而在os.OpenFile获得的文件句柄之上进行一层封装,bufio,从名字上也能看出来是带缓存的io。websocket

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    file, _ := os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)

    //使用bufio.NewReader进行一层包装
    reader := bufio.NewReader(file)
    //首先这个reader,能够像file同样,使用Read方法
    //然而reader还但是按照指定字符来读,好比我想一行一行读,就能够指定换行符来读
    for{
        //返回string和error
        s, err := reader.ReadString('\n') //表示每读到\n就中止
        //这里使用print,由于文件自己有换行符,println自带换行,因此使用print
        fmt.Print("读取一行:", s)
        /*
        读取一行:白色相簿什么的,已经无所谓了。
        读取一行:由于已经再也不有歌,值得去唱了。
        读取一行:传达不了的恋情,已经不须要了。
        读取一行:由于已经再也不有人,值得去爱了。
         */
        if err != nil {
            if err == io.EOF{
                break
            } else {
                panic(err)
            }
        }
    }
}
package main

import (
    "bufio"
    "bytes"
    "fmt"
    "os"
)

func main() {
    file, _ := os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)

    //除了NewReader,还有一个NewScanner
    scanner := bufio.NewScanner(file)
    for scanner.Scan(){
        //能够看到咱们使用println打印,行与行之间没有空隙,说明scanner.Text()没有把换行符读进去。
        fmt.Println(scanner.Text())
        /*
        白色相簿什么的,已经无所谓了。
        由于已经再也不有歌,值得去唱了。
        传达不了的恋情,已经不须要了。
        由于已经再也不有人,值得去爱了。
         */
    }

    //可是这都是一行一行读的,咱们能够写到缓存里面去
    //这个缓存使用bytes.Buffer{}来建立
    buf := bytes.Buffer{}
    file, _ = os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)
    scanner = bufio.NewScanner(file)
    for scanner.Scan(){
        //直接调用buf.WriteString便可
        buf.WriteString(scanner.Text())
        // 固然还可使用buf.Write写入字节,同时也可使用scanner.Bytes()获得字节。buf.Write(scanner.Bytes())
    }
    //能够调用buf.Bytes()拿到字节
    //也能够调用buf.String()拿到String
    fmt.Println(buf.String())  // 白色相簿什么的,已经无所谓了。由于已经再也不有歌,值得去唱了。传达不了的恋情,已经不须要了。由于已经再也不有人,值得去爱了。
    //由于没有读取换行符,因此是连在一块儿的

    //这里再提一下bytes.Buffer{},这是一个很是方便的字节缓存。用来组合字符串很是方便
    buffer := bytes.Buffer{}
    buffer.WriteString("哈哈")
    buffer.WriteString("呱呱")
    buffer.Write([]byte("嘻嘻"))
    fmt.Println(buffer.String())  // 哈哈呱呱嘻嘻
    fmt.Println(buffer.Bytes()) // [229 147 136 229 147 136 229 145 177 229 145 177 229 152 187 229 152 187]

    //固然buffer也有ReadString,和Read方法
    s, _ := buffer.ReadString('\n')
    fmt.Println(s) // 哈哈呱呱嘻嘻

    buffer.WriteString("你胸大,你先说")
    b := make([]byte, 1024)
    n, _  := buffer.Read(b)
    fmt.Println(string(b[: n])) // 你胸大,你先说
}

(3)使用ioutil模块

ioutil是一个很是强大模块app

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    file, _ := os.Open(`D:\komeijisatori\src\day3\whiteblum.txt`)
    // 直接将file丢进去,能够读取所有内容
    s, _ := ioutil.ReadAll(file)
    fmt.Println(string(s))
    /*
    白色相簿什么的,已经无所谓了。
    由于已经再也不有歌,值得去唱了。
    传达不了的恋情,已经不须要了。
    由于已经再也不有人,值得去爱了。
     */
    // 是否是很方便呢?其实还有更方便的
    //调用ReadFile,传入文件名直接获得字节数组和error。固然底层是使用了os.Open和ioutil.ReadAll
    s, _ = ioutil.ReadFile(`D:\komeijisatori\src\day3\whiteblum.txt`)
    fmt.Println(string(s))
    /*
    白色相簿什么的,已经无所谓了。
    由于已经再也不有歌,值得去唱了。
    传达不了的恋情,已经不须要了。
    由于已经再也不有人,值得去爱了。
     */
}

固然ioutil开能够写入文件curl

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
)

func main() {
    buf := bytes.Buffer{}
    buf.WriteString("明明是我先来的\n")
    buf.WriteString("为何会变成这样呢\n")
    buf.WriteString("何でそんなに慣れてんだよ\n")
    buf.WriteString("雪菜と何度もキースしたんだよ")
    //传入filename,content,权限
    _ = ioutil.WriteFile(`D:\komeijisatori\src\day3\whiteblum.txt`, buf.Bytes(), 0666)

    //读取出来看看
    s, _ := ioutil.ReadFile(`D:\komeijisatori\src\day3\whiteblum.txt`)
    fmt.Println(string(s))
    /*
    明明是我先来的
    为何会变成这样呢
    何でそんなに慣れてんだよ
    雪菜と何度もキースしたんだよ
     */
}

以前说ioutil很强大,是由于还有别的用处,好比读取目录

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    files, _ := ioutil.ReadDir(`C:\python37\Lib\site-packages\tornado`)
    //返回一个[]os.FileInfo和error
    for _, file := range files{
        if !file.IsDir(){
            fmt.Println(file.Name())
            /*
            __init__.py
            _locale_data.py
            auth.py
            autoreload.py
            concurrent.py
            curl_httpclient.py
            escape.py
            gen.py
            http1connection.py
            httpclient.py
            httpserver.py
            httputil.py
            ioloop.py
            iostream.py
            locale.py
            locks.py
            log.py
            netutil.py
            options.py
            process.py
            py.typed
            queues.py
            routing.py
            simple_httpclient.py
            speedups.cp37-win_amd64.pyd
            tcpclient.py
            tcpserver.py
            template.py
            testing.py
            util.py
            web.py
            websocket.py
            wsgi.py
             */
        }
    }
}