Go?文件讀取和寫入操作全面講解
Go 文件的讀取操作
os 包 和 bufio 包
Go 標(biāo)準(zhǔn)庫(kù)的 os 包,為我們提供很多操作文件的函數(shù),如 Open(name) 打開文件、Create(name) 創(chuàng)建文件等函數(shù),與之對(duì)應(yīng)的是 bufio 包,os 包是直接對(duì)磁盤進(jìn)行操作的,而 bufio 包則是帶有緩沖的操作,不用每次都去操作磁盤。
os.Open 與 os.OpenFile 以及 File.Read
Open(name string) (*File, error)通過 文件名 或 文件路徑+文件名 的形式打開一個(gè)文件,此文件只能用于讀操作,如果文件不存在則返回
PathError。- 參數(shù)
name為文件名或文件路徑+文件名。 - 返回值
*File為一個(gè)File結(jié)構(gòu)體的指針類型,通過指針可以對(duì)文件進(jìn)行讀寫等操作。
- 參數(shù)
返回值
`error` 為打開文件的過程中產(chǎn)生的錯(cuò)誤。
OpenFile(name string, flag int, perm FileMode) (*File, error)
通過指定 文件名 或 文件路徑+文件名、文件操作模式、文件權(quán)限三個(gè)參數(shù)打開一個(gè)文件,之后可對(duì)此文件進(jìn)行讀寫操作。
- 參數(shù)
name為文件名或文件路徑+文件名。 - 參數(shù)
flag為指定文件操作模式,可選值有O_RDONLY→ 只讀操作、O_WRONLY→ 只寫操作、O_RDWR→ 讀寫操作、O_APPEND→ 寫入時(shí)向文件追加數(shù)據(jù)、O_CREATE→ 如果不存在,則創(chuàng)建一個(gè)新文件等。 - 參數(shù)
perm參數(shù)表示文件的模式和權(quán)限,例如0666為讀寫權(quán)限。如果對(duì)文件權(quán)限所對(duì)應(yīng)的數(shù)字不了解,可以去學(xué)習(xí)一下。 - 返回值
*File為一個(gè)File結(jié)構(gòu)體的指針類型,通過指針可以對(duì)文件進(jìn)行讀寫等操作。 - 返回值
error為打開文件的過程中產(chǎn)生的錯(cuò)誤。
File.Read(b []byte) (n int, err error)
讀取與 b 等長(zhǎng)度的字節(jié),并存儲(chǔ)到 b 里面。
- 參數(shù)
b為一個(gè)切片數(shù)組,用于指定讀取長(zhǎng)度和存儲(chǔ)字節(jié)數(shù)據(jù)。 - 返回值
n為所讀取字節(jié)的長(zhǎng)度。 - 返回值
error為讀取字節(jié)的過程中產(chǎn)生的錯(cuò)誤。
讀取文件操作
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("1.txt")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
data := make([]byte, 11)
count, err := file.Read(data)
if err != nil {
return
}
fmt.Println("字節(jié)數(shù)據(jù):", data) // [72 101 108 108 111 32 119 111 114 108 100]
fmt.Println("字符串?dāng)?shù)據(jù):", string(data)) // Hello world
fmt.Println("所獲取字節(jié)的長(zhǎng)度:", count) // 11
}執(zhí)行結(jié)果:
字節(jié)數(shù)據(jù): [72 101 108 108 111 32 119 111 114 108 100]
字符串?dāng)?shù)據(jù): Hello world
所獲取字節(jié)的長(zhǎng)度: 11
- 首先通過
Open函數(shù)打開1.txt文件,用file變量接收,默認(rèn)為可讀模式; - 然后創(chuàng)建一個(gè)長(zhǎng)度為
11的字節(jié)切片,接著通過file變量的方法Read讀取長(zhǎng)度為11的字節(jié)數(shù)據(jù)。os.Open("1.txt")等價(jià)于os.OpenFile("1.txt", os.O_RDONLY, 0)。 - 最后打印讀取到的數(shù)據(jù),文件操作完畢之后,需要關(guān)閉文件
file.Close()。
bufio.NewReader 和 Reader.ReadString
讀取文件,建議使用 bufio.NewReader 和 Reader.ReadString,減少磁盤的操作。
NewReader(rd io.Reader) *Reader獲取一個(gè)有緩沖區(qū)的Reader指針變量,緩沖區(qū)默認(rèn)大小為4096字節(jié)。通過變量可以對(duì)數(shù)據(jù)進(jìn)行讀操作。- 參數(shù)
rd為一個(gè)接口,實(shí)現(xiàn)這個(gè)接口的數(shù)據(jù)類型變量都可以作為參數(shù),例如上面提到的File。 - 返回值
*Reader為Reader結(jié)構(gòu)體的指針,通過指針可以讀取緩沖區(qū)的數(shù)據(jù)。
- 參數(shù)
ReadString(delim byte) (string, error)讀取數(shù)據(jù),直到第一次遇到分隔符delim為止。讀取過程中發(fā)生錯(cuò)誤會(huì)返回EOF錯(cuò)誤信息。- 參數(shù)
delim為分隔符,每次讀取時(shí)遇到分隔符就會(huì)終止。 - 第一個(gè)返回值為所讀取的內(nèi)容,內(nèi)容包括分隔符。
- 第二個(gè)返回值為讀取過程中產(chǎn)生的錯(cuò)誤信息。
- 參數(shù)
讀取文件操作
1.txt 文件的內(nèi)容為:
Hello world
Hello Golang
Hello Gopher
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
func main() {
file, err := os.OpenFile("1.txt", os.O_RDONLY, 0)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
reader := bufio.NewReader(file)
for {
if lineData, err := reader.ReadString('\n'); err != nil {
if err == io.EOF {
// 因?yàn)槭且該Q行符為分隔符,如果最后一行沒有換行符,那么返回 io.EOF 錯(cuò)誤時(shí),也是可能讀到數(shù)據(jù)的,因此判斷一下是否讀到了數(shù)據(jù)
if len(lineData) > 0 {
fmt.Println(lineData)
}
break
}
} else {
fmt.Println(strings.TrimRight(lineData, "\n"))
}
}
}執(zhí)行結(jié)果:
Hello World
Hello Golang
Hello Gopher
- 首先通過
OpenFile函數(shù)打開1.txt文件,用file變量接收,指定為可讀模式; - 然后通過
NewReader函數(shù)創(chuàng)建一個(gè)緩沖區(qū),將默認(rèn)長(zhǎng)度的字節(jié)讀取到緩沖區(qū)中; - 接著通過
Reader結(jié)構(gòu)體的方法ReadString,以\n為分隔符,按行讀取數(shù)據(jù),然后打印數(shù)據(jù)。 - 其中有一個(gè)注意點(diǎn)就是,因?yàn)槭且該Q行符為分隔符,如果最后一行沒有換行符,那么返回
io.EOF錯(cuò)誤時(shí),也是可能讀到數(shù)據(jù)的,因此需要判斷一下是否讀到了數(shù)據(jù)。
Go 文件的寫入操作
File.Write、File.WriteString、File.WriteAt
File.Write(b []byte) (n int, err error)直接操作磁盤往文件里寫入數(shù)據(jù),寫入單位為字節(jié)。
b參數(shù):寫入的數(shù)據(jù),類型為字節(jié)切片。- 返回值
n:寫入的字節(jié)數(shù)。 - 返回值
err:寫入數(shù)據(jù)的過程中產(chǎn)生的錯(cuò)誤。
File.WriteString(s string) (n int, err error)直接操作磁盤往指定文件里寫入數(shù)據(jù),寫入單位為字符串。
s參數(shù):寫入的字符串?dāng)?shù)據(jù)。- 返回值
n:寫入的字節(jié)數(shù)。 - 返回值
err:寫入數(shù)據(jù)的過程中產(chǎn)生的錯(cuò)誤。
File.WriteAt(b []byte, off int64) (n int, err error)從指定位置
off往文件里順序?qū)懭霐?shù)據(jù),如果某個(gè)偏移量上有數(shù)據(jù),則會(huì)覆蓋。b參數(shù):寫入的數(shù)據(jù),類型為字節(jié)切片。off參數(shù):偏移量,從此位置開始寫入數(shù)據(jù)。- 返回值
n:寫入的字節(jié)數(shù)。 - 返回值
err:寫入數(shù)據(jù)的過程中產(chǎn)生的錯(cuò)誤。
文件寫入操作
import (
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("test.txt", os.O_CREATE, 0)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
count, err := file.Write([]byte{'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\n'})
if err != nil {
return
}
fmt.Printf("寫入了 %d 字節(jié)\n", count)
count, err = file.WriteString("Hello Golang")
if err != nil {
return
}
fmt.Printf("寫入了長(zhǎng)度為 %d 的字符串\n", count)
count, err = file.WriteAt([]byte{'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, 0)
if err != nil {
return
}
fmt.Printf("寫入了 %d 字節(jié)\n", count)
}- 首先打開
test.txt文件,指定的模式為os.O_CREATE,如果文件不存在則會(huì)自動(dòng)創(chuàng)建; - 然后通過
Write方法以字符的形式往文件里寫入Hello World\n的內(nèi)容;
接著通過 WriteString 方法以字符串的形式往文件里寫入 Hello Golang 內(nèi)容;此時(shí)文件里的內(nèi)容如下所示:
Hello World
Hello Golang
最后通過 WriteAt 方法,指定從偏移量為 0 的位置開始寫入數(shù)據(jù) xxxxxxxxxxx,由于 0 以及之后位置都有數(shù)據(jù),因此原有數(shù)據(jù)被覆蓋了。最后文件的內(nèi)容為:
xxxxxxxxxxx
Hello Golang
File.Seek
File.Seek(offset int64, whence int)相對(duì)于開頭位置或當(dāng)前位置或末尾位置,將設(shè)置當(dāng)前讀或?qū)懙钠屏吭O(shè)置為
offset。offset參數(shù):所要設(shè)置的偏移量。whence:相對(duì)于哪個(gè)位置開始設(shè)置偏移量的標(biāo)志,可選值為0→ 開頭位置,1→ 當(dāng)前位置,2→ 末尾位置。
應(yīng)用
import (
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("test.txt", os.O_CREATE, 0)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
_, err = file.WriteString("G0lang")
if err != nil {
return
}
_, err = file.Seek(1, 0)
if err != nil {
fmt.Println(err)
return
}
_, err = file.Write([]byte{'o'})
if err != nil {
fmt.Println(err)
return
}
}- 打開
test.txt文件,指定的模式為os.O_CREATE,如果文件不存在則會(huì)自動(dòng)創(chuàng)建; - 使用
WriteString方法往文件里寫入G0lang字符串; - 此時(shí)發(fā)現(xiàn)第二個(gè)字符錯(cuò)了,
0應(yīng)該改成o;此時(shí)的偏移量是指向尾部的;使用Seek方法將偏移量移到第二個(gè)位置,然后寫入字符o,由于當(dāng)前位置已有數(shù)據(jù)0,因此o將會(huì)覆蓋0;
bufio.NewWriter、Writer.WriteString、Writer.Flush
如果需要多次執(zhí)行寫入文件的操作,推薦使用 bufio 里的 Writer 結(jié)構(gòu)體去操作,它會(huì)開辟一個(gè)緩沖區(qū),默認(rèn)大小為 4096 字節(jié)。在數(shù)據(jù)沒有被刷入磁盤之前,所寫入的數(shù)據(jù)都會(huì)暫時(shí)保存到緩沖區(qū)里。
NewWriter(w io.Writer) *Writer開辟一個(gè)默認(rèn)值為
4096字節(jié)的緩沖區(qū),用于暫存寫入文件的數(shù)據(jù)內(nèi)容,返回一個(gè)Writer結(jié)構(gòu)體的指針變量w參數(shù):類型為Writer接口,實(shí)現(xiàn)這個(gè)接口的數(shù)據(jù)類型變量都可以作為參數(shù),例如File。- 返回值
*Writer:一個(gè)Writer結(jié)構(gòu)體的指針變量,通過該變量可以往緩沖區(qū)里寫入數(shù)據(jù)。
Writer.WriteString(s string) (int, error)往緩沖區(qū)寫入內(nèi)容的方法。
- 參數(shù)
s為寫入的字符串。 - 第一個(gè)返回值為寫入的字節(jié)數(shù)。
- 第二個(gè)返回值為寫入數(shù)據(jù)的過程中產(chǎn)生的錯(cuò)誤。
- 參數(shù)
Writer.Flush() error將所有的緩存數(shù)據(jù)寫入磁盤。
- 返回值為數(shù)據(jù)寫入磁盤的過程中產(chǎn)生的錯(cuò)誤。
文件寫入操作
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("test.txt", os.O_CREATE, 0)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
writer := bufio.NewWriter(file)
_, err = writer.WriteString("Hello World\n")
if err != nil {
fmt.Println(err)
return
}
_, err = writer.WriteString("Hello Golang\n")
if err != nil {
fmt.Println(err)
return
}
_, err = writer.WriteString("Hello Gopher\n")
if err != nil {
fmt.Println(err)
return
}
writer.Flush()
}- 首先打開
test.txt文件,指定的模式為os.O_CREATE,如果文件不存在則會(huì)自動(dòng)創(chuàng)建; - 然后使用
NewWriter函數(shù)獲取一個(gè)Writer結(jié)構(gòu)體的指針變量writer; - 接著通過
writer的WriteString方法將內(nèi)容保存到緩沖區(qū)里; - 最后調(diào)用
Flush方法,將所有的緩存數(shù)據(jù)寫入磁盤。
小結(jié)
文件的讀取操作推薦 bufio 包里的 NewReader 函數(shù)和 Reader 結(jié)構(gòu)體的方法 ReadString,能減少對(duì)磁盤的操作,高效讀取數(shù)據(jù)。
文件的寫入操作推薦 bufio.NewWriter、Writer.WriteString、Writer.Flush,使用它們代替 File 結(jié)構(gòu)體里的寫入方法,可以不用頻繁操作磁盤,提高寫入效率。
以上就是Go 文件讀取和寫入操作全面的詳細(xì)內(nèi)容,更多關(guān)于Go 文件的讀取和寫入操作的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語(yǔ)言創(chuàng)建、初始化數(shù)組的常見方式匯總
這篇文章主要介紹了Go語(yǔ)言創(chuàng)建、初始化數(shù)組的常見方式,實(shí)例匯總了Go語(yǔ)言操作數(shù)組的常見技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
詳解如何在Golang中監(jiān)聽多個(gè)channel
這篇文章主要為大家詳細(xì)介紹了如何在Golang中實(shí)現(xiàn)監(jiān)聽多個(gè)channel,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03
Go語(yǔ)言到底有沒有引用傳參(對(duì)比 C++ )
這篇文章主要介紹了Go 到底有沒有引用傳參(對(duì)比 C++ ),需要的朋友可以參考下2017-09-09
Golang使用gin框架實(shí)現(xiàn)一個(gè)完整的聊天室功能
由于我們項(xiàng)目的需要,我就研究了一下關(guān)于websocket的相關(guān)內(nèi)容,去實(shí)現(xiàn)一個(gè)聊天室的功能,經(jīng)過幾天的探索,現(xiàn)在使用Gin框架實(shí)現(xiàn)了一個(gè)完整的聊天室+消息實(shí)時(shí)通知系統(tǒng),感興趣的小伙伴歡迎閱讀本文2023-08-08
go語(yǔ)言fasthttp使用實(shí)例小結(jié)
fasthttp?是一個(gè)使用?Go?語(yǔ)言開發(fā)的?HTTP?包,主打高性能,針對(duì)?HTTP?請(qǐng)求響應(yīng)流程中的?hot?path?代碼進(jìn)行了優(yōu)化,下面我們就來介紹go語(yǔ)言fasthttp使用實(shí)例小結(jié),感興趣的朋友跟隨小編一起看看吧2024-03-03

