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
             */
        }
    }
}
相關文章
相關標籤/搜索