網站首頁 編程語言 正文
一、概念
文件是數據源(保存數據的地方)的一種,文件最主要的作用就是保存數據。
文件在程序中是以流的形式來操作的。
- 輸入流和輸出流
- 流:數據在數據源(文件)和程序(內存)之間經歷的路徑
- 輸入流:數據從數據源(文件)到程序(內存)的路徑
- 輸出流:數據從程序(內存)到數據源(文件)的路徑
二、讀取文件操作
2.1 打開和關閉文件
打開文件:
func Open(filename string) (file *File, err error)
Open打開一個文件用于讀取。如果操作成功,返回的文件對象的方法可用于讀取數據;對應的文件描述符具有O_RDONLY
模式。如果出錯,錯誤底層類型是*PathError
。
關閉文件:
func (f *File) Close() error
Close關閉文件f,使文件不能用于讀寫。它返回可能出現的錯誤。
示例:
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
之后再執行。 - 在
defer
歸屬的函數即將返回時,將延遲處理的語句按defer
的逆序進行執行,也就是說,先被defer
的語句最后被執行,最后被?defer
的語句,最先被執行。
2.2 file.Read() 讀取文件
Read 方法定義
func (f *File) Read(b []byte) (n int, err error)
從文件對象中讀取長度為b的字節,返回當前讀到的字節數以及錯誤信息。因此使用該方法需要先初始化一個符合內容大小的空的字節列表。讀取到文件的末尾時,該方法返回0,io.EOF
。
ReadAt方法定義
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
從文件的off偏移量開始讀取長度為b的字節。返回讀取到字節數以及錯誤信息。當讀取到的字節數n小于想要讀取字節的長度len(b)
的時候,該方法將返回非空的error。當讀到文件末尾時,err返回io.EOF。
- b:是指定字節長度的緩沖區
- off:int64類型的偏移量,從此位置開始讀取。
注意:ReadAt 絕對不允許出現,沒有讀滿 buffer,又非 EOF,又沒有 err 的情況發生,這個是接口語義明確規定的,這是一個非常細節的區別。
一次性讀取
適用于讀取較小文件使用:
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、當函數退出時,及時關閉file //使用 defer 內置函數 當函數退出時才會調用,要及時關閉否則會內存泄露 defer file.Close() //2、使用Read方法讀取數據,注意一次只會讀取128個字節 tmp := make([]byte, 128) n, err := file.Read(tmp) //使用ReadAt方法讀取數據,注意一次只會讀取6個字節 //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 字節數據\n", n) fmt.Println(string(tmp[:n])) }
運行結果:
讀取了 13 字節數據
Hello Golang!
循環讀取
使用 for 循環讀取文件中的所有數據:
package main import ( "fmt" "io" "os" ) //循環讀取文件 func main() { //只讀方式打開當前目錄下的test.txt file, err := os.Open("test.txt") if err != nil { fmt.Println("open file failed!,err:",err) return } //關閉文件 defer file.Close() //循環讀取文件 var content []byte //使用Read方法讀取數據,注意一次只會讀取128個字節 tmp := make([]byte, 128) for { n, err := file.Read(tmp) //每次讀取128個字節 if err == io.EOF { fmt.Println("文件讀取完畢") break } if err != nil { fmt.Println("read file failed,err:",err) return } //每次讀取的內容都追加到已知的byte切片中 content = append(content,tmp[:n]...) } //將byte類型轉換結果,打印結果 fmt.Println(string(content)) }
運行結果:
文件讀取完畢
水陸草木之花,可愛者甚蕃。晉陶淵明獨愛菊。自李唐來,世人甚愛牡丹。
予獨愛蓮之出淤泥而不染,濯清漣而不妖,中通外直,不蔓不枝,香遠益清,亭亭凈植,可遠觀而不可褻玩焉。予謂菊,花之隱逸者也;牡丹,花之富貴者也;蓮,花之君子者也。
噫!菊之愛,陶后鮮有聞。蓮之愛,同予者何人?牡丹之愛,宜乎眾矣!
說明:
這里的循環讀取文件其實就是一個不斷追加的過程,將每次讀取的128個字節追加到預先定義好的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)
參數
返回值:
使用 NewReader 讀取文件時,首先,需要打開文件,接著, 使用打開的文件返回的文件句柄當作?函數參數?傳入 NewReader。
最后,使用 NewReader 返回的 reader 對象調用 Read 來讀取文件。文件讀取結束的標志是返回的 n 等于 0,因此,如果需要讀取整個文件內容,那么我們需要使用?for 循環?不停的讀取文件,直到 n 等于 0。
- file:要讀取的文件句柄;
- buf:讀取的數據存放的緩沖區。
- 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 } //關閉文件,避免內存泄露 defer file.Close() //通過bufio緩沖區讀取文件 reader := bufio.NewReader(file) //建立緩沖區,將文件內容放入到緩沖區 //循環讀取文件信息 for { line, err := reader.ReadString('\n') //讀到一個換行就結束 if err == io.EOF { //io.EOF 表示文件的末尾 //輸出最后的內容 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
?方法一次性將文件讀取到內存中,只需要將文件名作為參數傳入。
示例:
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)) }
運行結果:
水陸草木之花,可愛者甚蕃。晉陶淵明獨愛菊。自李唐來,世人甚愛牡丹。
予獨愛蓮之出淤泥而不染,濯清漣而不妖,中通外直,不蔓不枝,香遠益清,亭亭凈植,可遠觀而不可褻玩焉。
予謂菊,花之隱逸者也;牡丹,花之富貴者也;蓮,花之君子者也。
噫!菊之愛,陶后鮮有聞。蓮之愛,同予者何人?牡丹之愛,宜乎眾矣!
注意:如果文件比較大,一次性讀取整個文件會占用很大的內存,影響執行效率。
建議讀取小文件時使用,不太適用于大文件的讀取。
效率比較
- 當文件較小(KB 級別)時,ioutil > bufio > file.Read()。
- 當文件大小比較常規(MB 級別)時,三者差別不大,但 bufio 優勢已經顯現出來。
- 當文件較大(GB 級別)時,bufio > file.Read()> ioutil。
當讀取小文件時,使用ioutil
效率明顯優于file.Read()
和bufio
,但如果是大文件,bufio
讀取會更快,效率更高。
三、寫入文件操作
3.1 os.OpenFile()函數
語法:
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
參數
os.OpenFile()
函數能夠以指定模式打開文件,從而實現文件寫入相關功能。
- name:要文件路徑+文件名;
- flag:打開文件的模式,只讀、讀寫等;
- perm:文件權限,一個八進制數。r(讀)04,W(寫)02,x(執行)01。
模式flag種類:
模式 | 含義 |
---|---|
os.O_WRONLY | 只寫 |
os.O_CREATE | 如果不存在文件,創建文件 |
os.O_RDONLY | 只讀 |
os.O_RDWR | 可讀可寫 |
os.O_TRUNC | 打開時清空文件原先內容 |
os.O_APPEND | 追加 |
若同時想用多種可用|
拼接不同模式。
文件權限perm:
使用4位8進制數
來表示三種類型用戶的權限,首位取0,形式即0XXX
。
- 第一個X表示的是文件所有者的權限;
- 第二個X表示的是組用戶的權限;
- 第三個X表示的是其他用戶的權限。
每位數字所代表的權限:讀r=4,寫w=2,可執行x=1
數字 | r | w | x | 權限 |
---|---|---|---|---|
0 | - | - | - | 所有權限均無 |
1 | - | - | x | 可執行 |
2 | - | w | - | 可寫 |
3 | - | w | x | 可寫,可執行 |
4 | r | - | - | 可讀 |
5 | r | - | x | 可讀,可執行 |
6 | r | w | - | 可讀,可寫 |
7 | r | w | x | 可讀,可寫,可執行 |
常使用的0644
(-rw-r--r--
),表示文件所有者可讀寫,同組用戶及其他用戶只可讀。
3.2 Write和WriteString 方式寫入
Write語法:
func (file *File) Write(b []byte) (n int, err Error)
參數
返回值:
使用 Write 方法寫文件,接受的?參數?是一個要寫入的文件內容的?字節?數組。如果寫入成功,返回成功寫入的字節數,如果寫入失敗,返回?error?信息。
WriteString語法:
func (f *File) WriteString(s string) (n int, err error)
參數
返回值:
使用 WriteString 方法寫文件,接受的參數是一個要寫入的文件內容的?字符串。如果寫入成功,返回成功寫入的字節數,如果寫入失敗,返回 error 信息。
- file:文件對象
- b:要寫入的文件內容
- n: 成功寫入的字節數
- err:寫入失敗,則返回錯誤信息
- f:文件對象
- s:要寫入的文件內容
- n:成功寫入的字節數
- err:寫入失敗,則返回錯誤信息
示例:
package main import ( "fmt" "os" ) //創建并寫入數據 //Write 和 WriteString func main() { //os.O_CREATE|os.O_RDWR:如果不存在文件,創建文件,可讀可寫 //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)) //寫入字節切片數據 file.WriteString("直接寫入的字符串數據") //直接寫入字符串數據 }
3.3 bufio.NewWriter
語法:
func NewWriter(w io.Writer) *Writer
func (b *Writer) WriteString(s string) (int, error)
func (b *Writer) Flush() error
將要寫入的內容寫入緩存中,在執行flush的時候才會被寫到磁盤。
- 創建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、創建writer對象 writer := bufio.NewWriter(file) for i := 0; i < 10; i++ { writer.WriteString("Hello Golang\r\n") //3、將數據先寫入緩存 } writer.Flush() //4、將緩存中的內容寫入文件 }
3.4 ioutil.WriteFile
語法:
func WriteFile(filename string, data []byte, perm os.FileMode) error
參數
返回值
使用 WriteFile 方法寫文件,接受的第一個?參數?是一個?string 類型?的文件名,第二個參數是一個要寫入的文件內容的?byte?數組,最后一個參數是文件的權限。如果寫入成功,返回空的?error?信息,如果寫入失敗,返回 error 信息。
- filename:文件路徑+文件名稱
- data:要寫入的文件內容
- 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 進行復制 //編寫一個函數,接收兩個文件路徑 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" ) //復制數據 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) } //創建目錄 err02 := os.Mkdir("D:/aa", 0666) if err02 != nil { fmt.Println(err02) } //一次創建多個目錄 err03 := os.MkdirAll("D:/aa/bb/cc",0666) //創建多級目錄 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) } }
原文鏈接:https://juejin.cn/post/7123848469508259870
相關推薦
- 2023-01-30 vite?+?react?+typescript?環境搭建小白入門教程_React
- 2023-12-20 Mybatis中resultMap結果集的使用
- 2022-12-15 C++?Boost?Lambda表達式詳解_C 語言
- 2024-04-05 springboot注冊攔截器與返回統一標準響應格式
- 2022-05-08 SQL利用游標遍歷日期查詢的過程詳解_MsSql
- 2024-03-19 Linux中 find 命令詳解
- 2022-09-25 python?opencv實現圖像矯正功能_python
- 2022-03-21 oracle中commit之后進行數據回滾的方法_oracle
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支