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

