Golang文件讀寫操作詳情
一、概念
文件是數(shù)據(jù)源(保存數(shù)據(jù)的地方)的一種,文件最主要的作用就是保存數(shù)據(jù)。
文件在程序中是以流的形式來操作的。
- 輸入流和輸出流
- 流:數(shù)據(jù)在數(shù)據(jù)源(文件)和程序(內(nèi)存)之間經(jīng)歷的路徑
- 輸入流:數(shù)據(jù)從數(shù)據(jù)源(文件)到程序(內(nèi)存)的路徑
- 輸出流:數(shù)據(jù)從程序(內(nèi)存)到數(shù)據(jù)源(文件)的路徑
二、讀取文件操作
2.1 打開和關(guān)閉文件
打開文件:
func Open(filename string) (file *File, err error)
Open打開一個(gè)文件用于讀取。如果操作成功,返回的文件對(duì)象的方法可用于讀取數(shù)據(jù);對(duì)應(yīng)的文件描述符具有O_RDONLY
模式。如果出錯(cuò),錯(cuò)誤底層類型是*PathError
。
關(guān)閉文件:
func (f *File) Close() error
Close關(guān)閉文件f,使文件不能用于讀寫。它返回可能出現(xiàn)的錯(cuò)誤。
示例:
package main import ( "fmt" "os" ) func main() { //只讀方式打開當(dāng)前目錄下的test.txt file, err := os.Open("test.txt") if err != nil { fmt.Println("open file failed!,err:",err) } //返回的是一個(gè)指針 fmt.Println(&file) //關(guān)閉文件 //err = file.Close() //if err != nil{ // fmt.Println("close file failed!,err:",err) //} //為了防止文件忘記關(guān)閉,通常使用defer注冊(cè)文件關(guān)閉語句。 defer file.Close() // 關(guān)閉文件 }
運(yùn)行結(jié)果:
0xc0000ce018
defer 語句
defer
—般用于資源的釋放和異常的捕捉。defer
語句會(huì)將其后面跟隨的語句進(jìn)行延遲處理
;跟在defer
后面的語言將會(huì)在程序進(jìn)行最后的return
之后再執(zhí)行。- 在
defer
歸屬的函數(shù)即將返回時(shí),將延遲處理的語句按defer
的逆序進(jìn)行執(zhí)行,也就是說,先被defer
的語句最后被執(zhí)行,最后被defer
的語句,最先被執(zhí)行。
2.2 file.Read() 讀取文件
Read 方法定義
func (f *File) Read(b []byte) (n int, err error)
從文件對(duì)象中讀取長(zhǎng)度為b的字節(jié),返回當(dāng)前讀到的字節(jié)數(shù)以及錯(cuò)誤信息。因此使用該方法需要先初始化一個(gè)符合內(nèi)容大小的空的字節(jié)列表。讀取到文件的末尾時(shí),該方法返回0,io.EOF
。
ReadAt方法定義
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
從文件的off偏移量開始讀取長(zhǎng)度為b的字節(jié)。返回讀取到字節(jié)數(shù)以及錯(cuò)誤信息。當(dāng)讀取到的字節(jié)數(shù)n小于想要讀取字節(jié)的長(zhǎng)度len(b)
的時(shí)候,該方法將返回非空的error。當(dāng)讀到文件末尾時(shí),err返回io.EOF。
- b:是指定字節(jié)長(zhǎng)度的緩沖區(qū)
- off:int64類型的偏移量,從此位置開始讀取。
注意:ReadAt 絕對(duì)不允許出現(xiàn),沒有讀滿 buffer,又非 EOF,又沒有 err 的情況發(fā)生,這個(gè)是接口語義明確規(guī)定的,這是一個(gè)非常細(xì)節(jié)的區(qū)別。
一次性讀取
適用于讀取較小文件使用:
package main import ( "fmt" "io" "os" ) func main() { //1、只讀方式打開當(dāng)前目錄下的test2.txt file, err := os.Open("test2.txt") if err != nil { fmt.Println("open file failed!,err:",err) return } //3、當(dāng)函數(shù)退出時(shí),及時(shí)關(guān)閉file //使用 defer 內(nèi)置函數(shù) 當(dāng)函數(shù)退出時(shí)才會(huì)調(diào)用,要及時(shí)關(guān)閉否則會(huì)內(nèi)存泄露 defer file.Close() //2、使用Read方法讀取數(shù)據(jù),注意一次只會(huì)讀取128個(gè)字節(jié) tmp := make([]byte, 128) n, err := file.Read(tmp) //使用ReadAt方法讀取數(shù)據(jù),注意一次只會(huì)讀取6個(gè)字節(jié) //tmp := make([]byte, 6) //n, err := file.ReadAt(tmp,6) //io.EOF 表示文件的末尾 if err == io.EOF { fmt.Println("文件讀取完畢") return } if err != nil { fmt.Println("read file failed,err:",err) return } fmt.Printf("讀取了 %d 字節(jié)數(shù)據(jù)\n", n) fmt.Println(string(tmp[:n])) }
運(yùn)行結(jié)果:
讀取了 13 字節(jié)數(shù)據(jù)
Hello Golang!
循環(huán)讀取
使用 for 循環(huán)讀取文件中的所有數(shù)據(jù):
package main import ( "fmt" "io" "os" ) //循環(huán)讀取文件 func main() { //只讀方式打開當(dāng)前目錄下的test.txt file, err := os.Open("test.txt") if err != nil { fmt.Println("open file failed!,err:",err) return } //關(guān)閉文件 defer file.Close() //循環(huán)讀取文件 var content []byte //使用Read方法讀取數(shù)據(jù),注意一次只會(huì)讀取128個(gè)字節(jié) tmp := make([]byte, 128) for { n, err := file.Read(tmp) //每次讀取128個(gè)字節(jié) if err == io.EOF { fmt.Println("文件讀取完畢") break } if err != nil { fmt.Println("read file failed,err:",err) return } //每次讀取的內(nèi)容都追加到已知的byte切片中 content = append(content,tmp[:n]...) } //將byte類型轉(zhuǎn)換結(jié)果,打印結(jié)果 fmt.Println(string(content)) }
運(yùn)行結(jié)果:
文件讀取完畢
水陸草木之花,可愛者甚蕃。晉陶淵明獨(dú)愛菊。自李唐來,世人甚愛牡丹。
予獨(dú)愛蓮之出淤泥而不染,濯清漣而不妖,中通外直,不蔓不枝,香遠(yuǎn)益清,亭亭凈植,可遠(yuǎn)觀而不可褻玩焉。予謂菊,花之隱逸者也;牡丹,花之富貴者也;蓮,花之君子者也。
噫!菊之愛,陶后鮮有聞。蓮之愛,同予者何人?牡丹之愛,宜乎眾矣!
說明:
這里的循環(huán)讀取文件其實(shí)就是一個(gè)不斷追加的過程,將每次讀取的128個(gè)字節(jié)追加到預(yù)先定義好的content切片中,最后將切片轉(zhuǎn)換成string類型,進(jìn)行打印顯示。
2.3 bufio 讀取文件
語法:
//bufio.NewReader(rd io.Reader) *Reader r := bufio.NewReader(file) //func (b *Reader) ReadString(delim byte) (string, error) n, err := r.Read(buf)
參數(shù)
返回值:
使用 NewReader 讀取文件時(shí),首先,需要打開文件,接著, 使用打開的文件返回的文件句柄當(dāng)作 函數(shù)參數(shù) 傳入 NewReader。
最后,使用 NewReader 返回的 reader 對(duì)象調(diào)用 Read 來讀取文件。文件讀取結(jié)束的標(biāo)志是返回的 n 等于 0,因此,如果需要讀取整個(gè)文件內(nèi)容,那么我們需要使用 for 循環(huán) 不停的讀取文件,直到 n 等于 0。
- file:要讀取的文件句柄;
- buf:讀取的數(shù)據(jù)存放的緩沖區(qū)。
- n:讀取到的長(zhǎng)度
- err:讀取失敗,則返回錯(cuò)誤信息。
示例:
package main import ( "bufio" "fmt" "io" "os" ) //bufio讀取文件 func main() { //只讀方式打開當(dāng)前目錄下的test.txt file, err := os.Open("test.txt") if err != nil { fmt.Println("open file failed!,err:",err) return } //關(guān)閉文件,避免內(nèi)存泄露 defer file.Close() //通過bufio緩沖區(qū)讀取文件 reader := bufio.NewReader(file) //建立緩沖區(qū),將文件內(nèi)容放入到緩沖區(qū) //循環(huán)讀取文件信息 for { line, err := reader.ReadString('\n') //讀到一個(gè)換行就結(jié)束 if err == io.EOF { //io.EOF 表示文件的末尾 //輸出最后的內(nèi)容 if len(line) != 0 { fmt.Println(line) } fmt.Println("文件讀取完畢") break } if err != nil { fmt.Println("read file failed,err:",err) return } fmt.Println(line) } }
運(yùn)行結(jié)果:
水陸草木之花,可愛者甚蕃。晉陶淵明獨(dú)愛菊。自李唐來,世人甚愛牡丹。
予獨(dú)愛蓮之出淤泥而不染,濯清漣而不妖,中通外直,不蔓不枝,香遠(yuǎn)益清,亭亭凈植,可遠(yuǎn)觀而不可褻玩焉。
予謂菊,花之隱逸者也;牡丹,花之富貴者也;蓮,花之君子者也。
噫!菊之愛,陶后鮮有聞。蓮之愛,同予者何人?牡丹之愛,宜乎眾矣!
文件讀取完畢
2.4 ioutil 讀取文件
語法:
func ReadFile(name string) ([]byte, error)
- name:文件路徑地址
使用 io/ioutil.ReadFile
方法一次性將文件讀取到內(nèi)存中,只需要將文件名作為參數(shù)傳入。
示例:
package main import ( "fmt" "io/ioutil" ) //ioutil 讀取整個(gè)文件 func main() { content, err := ioutil.ReadFile("test.txt") if err != nil { fmt.Println("read failed,err:",err) return } fmt.Println(string(content)) }
運(yùn)行結(jié)果:
水陸草木之花,可愛者甚蕃。晉陶淵明獨(dú)愛菊。自李唐來,世人甚愛牡丹。
予獨(dú)愛蓮之出淤泥而不染,濯清漣而不妖,中通外直,不蔓不枝,香遠(yuǎn)益清,亭亭凈植,可遠(yuǎn)觀而不可褻玩焉。
予謂菊,花之隱逸者也;牡丹,花之富貴者也;蓮,花之君子者也。
噫!菊之愛,陶后鮮有聞。蓮之愛,同予者何人?牡丹之愛,宜乎眾矣!
注意:如果文件比較大,一次性讀取整個(gè)文件會(huì)占用很大的內(nèi)存,影響執(zhí)行效率。
建議讀取小文件時(shí)使用,不太適用于大文件的讀取。
效率比較
- 當(dāng)文件較小(KB 級(jí)別)時(shí),ioutil > bufio > file.Read()。
- 當(dāng)文件大小比較常規(guī)(MB 級(jí)別)時(shí),三者差別不大,但 bufio 優(yōu)勢(shì)已經(jīng)顯現(xiàn)出來。
- 當(dāng)文件較大(GB 級(jí)別)時(shí),bufio > file.Read()> ioutil。
當(dāng)讀取小文件時(shí),使用ioutil
效率明顯優(yōu)于file.Read()
和bufio
,但如果是大文件,bufio
讀取會(huì)更快,效率更高。
三、寫入文件操作
3.1 os.OpenFile()函數(shù)
語法:
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
參數(shù)
os.OpenFile()
函數(shù)能夠以指定模式打開文件,從而實(shí)現(xiàn)文件寫入相關(guān)功能。
- name:要文件路徑+文件名;
- flag:打開文件的模式,只讀、讀寫等;
- perm:文件權(quán)限,一個(gè)八進(jìn)制數(shù)。r(讀)04,W(寫)02,x(執(zhí)行)01。
模式flag種類:
模式 | 含義 |
---|---|
os.O_WRONLY | 只寫 |
os.O_CREATE | 如果不存在文件,創(chuàng)建文件 |
os.O_RDONLY | 只讀 |
os.O_RDWR | 可讀可寫 |
os.O_TRUNC | 打開時(shí)清空文件原先內(nèi)容 |
os.O_APPEND | 追加 |
若同時(shí)想用多種可用|
拼接不同模式。
文件權(quán)限perm:
使用4位8進(jìn)制數(shù)
來表示三種類型用戶的權(quán)限,首位取0,形式即0XXX
。
- 第一個(gè)X表示的是文件所有者的權(quán)限;
- 第二個(gè)X表示的是組用戶的權(quán)限;
- 第三個(gè)X表示的是其他用戶的權(quán)限。
每位數(shù)字所代表的權(quán)限:讀r=4,寫w=2,可執(zhí)行x=1
數(shù)字 | r | w | x | 權(quán)限 |
---|---|---|---|---|
0 | - | - | - | 所有權(quán)限均無 |
1 | - | - | x | 可執(zhí)行 |
2 | - | w | - | 可寫 |
3 | - | w | x | 可寫,可執(zhí)行 |
4 | r | - | - | 可讀 |
5 | r | - | x | 可讀,可執(zhí)行 |
6 | r | w | - | 可讀,可寫 |
7 | r | w | x | 可讀,可寫,可執(zhí)行 |
常使用的0644
(-rw-r--r--
),表示文件所有者可讀寫,同組用戶及其他用戶只可讀。
3.2 Write和WriteString 方式寫入
Write語法:
func (file *File) Write(b []byte) (n int, err Error)
參數(shù)
返回值:
使用 Write 方法寫文件,接受的 參數(shù) 是一個(gè)要寫入的文件內(nèi)容的 字節(jié) 數(shù)組。如果寫入成功,返回成功寫入的字節(jié)數(shù),如果寫入失敗,返回 error 信息。
WriteString語法:
func (f *File) WriteString(s string) (n int, err error)
參數(shù)
返回值:
使用 WriteString 方法寫文件,接受的參數(shù)是一個(gè)要寫入的文件內(nèi)容的 字符串。如果寫入成功,返回成功寫入的字節(jié)數(shù),如果寫入失敗,返回 error 信息。
- file:文件對(duì)象
- b:要寫入的文件內(nèi)容
- n: 成功寫入的字節(jié)數(shù)
- err:寫入失敗,則返回錯(cuò)誤信息
- f:文件對(duì)象
- s:要寫入的文件內(nèi)容
- n:成功寫入的字節(jié)數(shù)
- err:寫入失敗,則返回錯(cuò)誤信息
示例:
package main import ( "fmt" "os" ) //創(chuàng)建并寫入數(shù)據(jù) //Write 和 WriteString func main() { //os.O_CREATE|os.O_RDWR:如果不存在文件,創(chuàng)建文件,可讀可寫 //0666對(duì)應(yīng):-rw-rw-rw- file, err := os.OpenFile("D:/bb.txt", os.O_CREATE|os.O_RDWR, 0666) if err != nil { fmt.Println("open file failed,err:",err) return } defer file.Close() str := "Hello Golang\r\n" file.Write([]byte(str)) //寫入字節(jié)切片數(shù)據(jù) file.WriteString("直接寫入的字符串?dāng)?shù)據(jù)") //直接寫入字符串?dāng)?shù)據(jù) }
3.3 bufio.NewWriter
語法:
func NewWriter(w io.Writer) *Writer
func (b *Writer) WriteString(s string) (int, error)
func (b *Writer) Flush() error
將要寫入的內(nèi)容寫入緩存中,在執(zhí)行flush的時(shí)候才會(huì)被寫到磁盤。
- 創(chuàng)建writer實(shí)例
- 將信息寫入緩存
- 將緩沖寫入文件
示例:
package main import ( "bufio" "fmt" "os" ) //bufio.NewWriter func main() { //1、打開文件 file,err := os.OpenFile("D:/cc.txt",os.O_CREATE|os.O_TRUNC|os.O_WRONLY,0666) if err != nil { fmt.Println("open file failed,err:",err) return } //5、關(guān)閉文件流 defer file.Close() //2、創(chuàng)建writer對(duì)象 writer := bufio.NewWriter(file) for i := 0; i < 10; i++ { writer.WriteString("Hello Golang\r\n") //3、將數(shù)據(jù)先寫入緩存 } writer.Flush() //4、將緩存中的內(nèi)容寫入文件 }
3.4 ioutil.WriteFile
語法:
func WriteFile(filename string, data []byte, perm os.FileMode) error
參數(shù)
返回值
使用 WriteFile 方法寫文件,接受的第一個(gè) 參數(shù) 是一個(gè) string 類型 的文件名,第二個(gè)參數(shù)是一個(gè)要寫入的文件內(nèi)容的 byte 數(shù)組,最后一個(gè)參數(shù)是文件的權(quán)限。如果寫入成功,返回空的 error 信息,如果寫入失敗,返回 error 信息。
- filename:文件路徑+文件名稱
- data:要寫入的文件內(nèi)容
- perm:文件權(quán)限
- err:寫入失敗,則返回錯(cuò)誤信息
示例:
package main import ( "fmt" "io/ioutil" ) //ioutil.WriteFile func main() { str := "Hello Golang" err := ioutil.WriteFile("D:/dd.txt", []byte(str), 0666) if err != nil { fmt.Println("write file failed,err:",err) return } }
四、復(fù)制文件
4.1 通過ioutil進(jìn)行復(fù)制
package main import ( "fmt" "io/ioutil" ) //復(fù)制文件 //ioutil 進(jìn)行復(fù)制 //編寫一個(gè)函數(shù),接收兩個(gè)文件路徑 srcFileName dstFileName func CopyFile(srcFileName string,dstFileName string)(err error){ input, err := ioutil.ReadFile(srcFileName) if err != nil { fmt.Println(err) return err } err = ioutil.WriteFile(dstFileName, input, 0644) if err != nil { fmt.Println("Error creating",dstFileName) fmt.Println(err) return err } return nil } func main() { srcFile := "D:/aa.zip" dstFile := "D:/bb.zip" err := CopyFile(srcFile, dstFile) if err == nil { fmt.Printf("拷貝完成\n") }else { fmt.Printf("拷貝錯(cuò)誤 err=%v\n",err) } }
4.2 以文件流的方式復(fù)制文件
package main import ( "fmt" "io" "os" ) //復(fù)制數(shù)據(jù) func CopyFile(srcFileName string,dstFileName string)(err error){ source, _ := os.Open(srcFileName) destination, _ := os.OpenFile(dstFileName, os.O_CREATE|os.O_WRONLY, 0666) buf := make([]byte, 128) for { n, err := source.Read(buf) if err != nil && err != io.EOF { return err } if n == 0 { break } if _,err := destination.Write(buf[:n]); err != nil { return err } } return nil } func main() { srcFile := "D:/aa.zip" dstFile := "D:/bb.zip" err := CopyFile(srcFile, dstFile) if err == nil { fmt.Printf("拷貝完成\n") }else { fmt.Printf("拷貝錯(cuò)誤 err=%v\n",err) } }
五、其他操作
package main import ( "fmt" "os" ) func main() { //文件重命名 err01 := os.Rename("D:/aa.txt","D:/ee.txt") //只能同盤操作 if err01 != nil { fmt.Println(err01) } //創(chuàng)建目錄 err02 := os.Mkdir("D:/aa", 0666) if err02 != nil { fmt.Println(err02) } //一次創(chuàng)建多個(gè)目錄 err03 := os.MkdirAll("D:/aa/bb/cc",0666) //創(chuàng)建多級(jí)目錄 if err03 != nil { fmt.Println(err03) } //刪除目錄和文件 err04 := os.Remove("D:/ee.txt") if err04 != nil { fmt.Println(err04) } //一次刪除多個(gè)目錄或者文件 err05 := os.RemoveAll("D:/aa") if err05 != nil { fmt.Println(err05) } }
到此這篇關(guān)于Golang文件讀寫操作詳情的文章就介紹到這了,更多相關(guān)Go文件操作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go 實(shí)現(xiàn)百萬WebSocket連接的方法示例
這篇文章主要介紹了Go 實(shí)現(xiàn)百萬WebSocket連接的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08go語言題解LeetCode1299將每個(gè)元素替換為右側(cè)最大元素
這篇文章主要為大家介紹了go語言LeetCode刷題1299將每個(gè)元素替換為右側(cè)最大元素示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01對(duì)Golang中的runtime.Caller使用說明
這篇文章主要介紹了對(duì)Golang中的runtime.Caller使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12go程序部署到linux上運(yùn)行的實(shí)現(xiàn)方法
本文主要介紹了go程序部署到linux上運(yùn)行的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04MacOS下本地golang環(huán)境搭建詳細(xì)教程
這篇文章主要介紹了MacOS下本地golang環(huán)境搭建詳細(xì)教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09手把手教你用VS?code快速搭建一個(gè)Golang項(xiàng)目
Go語言是采用UTF8編碼的,理論上使用任何文本編輯器都能做Go語言開發(fā),下面這篇文章主要給大家介紹了關(guān)于使用VS?code快速搭建一個(gè)Golang項(xiàng)目的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04