作者:尹正傑
版權宣告:原創作品,謝絕轉載!否則將追究法律責任。
目錄
- 一.檔案的讀取操作
- 1.什麼是檔案
- 2.IO流型別概述
- 3.檔案的基本操作
- 3.1 開啟和關閉檔案
- 3.2 帶緩衝大小讀取檔案內容
- 3.3 迴圈讀取
- 4.ioutil包一次性讀取小檔案
- 4.1 ioutil包概述
- 4.2 ioutil讀取整個檔案
- 5.bufio包按行讀取檔案
- 二.檔案的寫入操作
- 1.檔案的開啟模式
- 2.Write和WriteString
- 3.bufio.NewWriter寫入檔案
- 4.WriteFile
- 三.檔案的複製操作
- 1.複製檔案內容案例
- 2.藉助
io.Copy()
實現一個複製檔案函式
一.檔案的讀取操作
1.什麼是檔案
計算機中的檔案是儲存在外部介質(通常是磁碟)上的資料集合,檔案分為文字檔案和二進位制檔案。
檔案是儲存資料的地方,是資料來源的一種,比如大家經常使用的word檔案,txt檔案,Excel,jpg,png,mp3,mp4,rmvb等都是檔案。
檔案最主要的做喲合格就是儲存資料,它既可以儲存一張圖片,也可以儲存影片,聲音等等。
2.IO流型別概述
如上圖所示,IO(Input/Output)流是程式和資料來源溝通的橋樑,IO流分為輸入流和輸出流兩個不同的方向。
輸入流一般指的是程式讀取原始檔的場景。
輸出流一般指的是程式寫入資料到目標檔案的場景。
3.檔案的基本操作
3.1 開啟和關閉檔案
package main
import (
"fmt"
"os"
)
func main() {
// 1.開啟檔案
file, err := os.Open("/etc/hosts")
if err != nil {
fmt.Printf("開啟檔案出錯, err= %v\n", err)
}
// 2.在程式退出前一定要關閉檔案以釋放資源
defer file.Close()
// 3.開啟檔案若沒錯,則可以對檔案進行一系列的操作
fmt.Printf("檔案物件: %v\n", file)
}
3.2 帶緩衝大小讀取檔案內容
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 只讀方式開啟當前目錄下的hosts檔案
file, err := os.Open("/etc/hosts")
if err != nil {
fmt.Println("開啟檔案失敗!, err = ", err)
return
}
// 為了防止檔案忘記關閉導致記憶體洩漏,我們通常使用defer註冊檔案關閉語句。
defer file.Close()
// 定義一個緩衝區的位元組切片,此處咱們可以一次性讀取4096個位元組大小資料區域。
var cache = make([]byte, 4096)
/*
使用Read方法讀取資料,需要專遞一個位元組切片,該切片大小表示一次性讀取的檔案內容的大小。
- 1.當我們傳遞的位元組切片大小較小時,儘管沒有讀取完檔案的所有內容,也不會讀取超出的內容喲。
- 2、當我們傳遞的位元組切片大小較大時,會將檔案的內容全部讀取出來,並不會重複讀取檔案的內容喲~
*/
n, err := file.Read(cache)
if err == io.EOF {
fmt.Println("檔案讀完了")
return
}
if err != nil {
fmt.Println("read file failed, err:", err)
return
}
fmt.Printf("讀取了%d位元組資料\n", n)
fmt.Printf("檔案內容:\n%s", string(cache[:n]))
}
3.3 迴圈讀取
package main
import (
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("/etc/hosts")
if err != nil {
fmt.Println("open file failed!, err:", err)
return
}
defer file.Close()
var content []byte
var tmp = make([]byte, 128)
// 使用for迴圈讀取檔案中的所有資料。
for {
// 一次性讀取的128位元組的大小
buf, err := file.Read(tmp)
if err == io.EOF {
fmt.Println("檔案讀完了")
break
}
if err != nil {
fmt.Println("檔案讀取失敗,錯誤:", err)
return
}
// 每次讀取buf大小後都追加到content切片中
content = append(content, tmp[:buf]...)
}
// 將所有的內容讀取到content切片後,再統一列印
fmt.Printf("檔案內容:\n%s", string(content))
}
4.ioutil包一次性讀取小檔案
4.1 ioutil包概述
讀取檔案的內容並顯示在終端(使用ioutil一次性將整個檔案讀入到記憶體中),這種方式適用於檔案不大的情況。
相關方法的函式有"ioutil.ReadFile"。
4.2 ioutil讀取整個檔案
package main
import (
"fmt"
"io/ioutil"
)
func main() {
// "io/ioutil"包的ReadFile方法能夠讀取完整的檔案,只需要將檔名作為引數傳入。
content, err := ioutil.ReadFile("/etc/hosts")
if err != nil {
fmt.Println("讀取檔案出錯, err:", err)
return
}
// 讀取檔案的內容並顯示在終端(使用ioutil一次性將整個檔案讀入到記憶體中),這種方式適用於檔案不大的情況。
fmt.Printf("檔案內容: \n%v", string(content))
}
5.bufio包按行讀取檔案
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
// 開啟檔案
file, err := os.Open("/etc/hosts")
if err != nil {
fmt.Println("檔案開啟失敗, err=", err)
return
}
// 當函式退出是,讓file關閉,防止記憶體洩漏;
defer file.Close()
// 建立一個IO流,bufio是在file的基礎上封裝了一層API,支援更多的功能。
reader := bufio.NewReader(file)
// 讀取操作
for {
// 按行讀取,注意是字元'\n'。
line, err := reader.ReadString('\n')
// 表示已經讀取到檔案的結尾
if err == io.EOF {
if len(line) != 0 {
fmt.Println(line)
}
fmt.Println("檔案讀完了")
break
}
if err != nil {
fmt.Println("讀取檔案失敗, err:", err)
return
}
// 如果沒有讀取到檔案結尾的話,就正常輸出檔案內容即可。
fmt.Print(line)
}
//
fmt.Println("檔案讀取成功,程式執行結束...")
}
二.檔案的寫入操作
1.檔案的開啟模式
模式 | 含義 |
---|---|
os.O_RDONLY |
只讀模式開啟檔案 |
os.O_WRONLY |
只寫模式開啟檔案 |
os.O_RDWR |
讀寫模式開啟檔案 |
os.O_APPEND |
寫操作時將資料附加到檔案尾部 |
os.O_CREATE |
建立檔案 |
os.EXCL |
和os.OCREATE 配合使用,檔案必須不存在 |
os.SYNC |
開啟檔案用於同步I/O |
os.O_TRUNC |
如果檔案存在,則開啟檔案時先清空再開啟 |
os.OpenFile()函式能夠以指定模式開啟檔案,從而實現檔案寫入相關功能。
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
...
}
相關引數說明:
- name:
要開啟的檔名
- flag:
開啟檔案的模式,常見的模式如上表所示。
- perm:
檔案許可權,一個八進位制數。r(讀)04,w(寫)02,x(執行)01。
2.Write和WriteString
package main
import (
"fmt"
"os"
)
func main() {
// 以只寫的模式開啟檔案
file, err := os.OpenFile("blog.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
if err != nil {
fmt.Println("檔案開啟失敗, err= ", err)
return
}
defer file.Close()
str := "部落格地址: https://www.cnblogs.com/yinzhengjie\n\n"
//寫入位元組切片資料
file.Write([]byte(str))
//直接寫入字串資料
file.WriteString("Go影片教學地址: https://www.bilibili.com/video/BV1bwhve7EPJ/\n")
}
3.bufio.NewWriter寫入檔案
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// 以只寫的模式開啟檔案
file, err := os.OpenFile("./yinzhengjie.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
// 判斷檔案是否開啟失敗
if err != nil {
fmt.Println("open file failed, err:", err)
return
}
// 及時將檔案關閉,防止記憶體洩漏
defer file.Close()
// 寫入操作,獲取一個IO流,帶緩衝區的輸出流
writer := bufio.NewWriter(file)
// 將資料寫入緩衝區
for i := 0; i < 10; i++ {
writer.WriteString("部落格地址: https://www.cnblogs.com/yinzhengjie\n")
}
// 將緩衝區的資料重新整理到磁碟
writer.Flush()
// tips: 檢視檔案開啟模式,需要懂Linux基礎知識
mode := os.FileMode(0644).String()
fmt.Printf("mode: 0644 = %s\n", mode)
}
4.WriteFile
package main
import (
"fmt"
"io/ioutil"
)
func main() {
str := "{\"尹正傑部落格地址\": \"https://www.cnblogs.com/yinzhengjie\"}"
// ioutil.WriteFile寫入檔案時,若檔案已存在或者有內容,會直接將原始檔清空喲~
err := ioutil.WriteFile("./blog.json", []byte(str), 0666)
if err != nil {
fmt.Println("檔案開啟失敗,錯誤 = ", err)
return
}
}
三.檔案的複製操作
1.複製檔案內容案例
package main
import (
"fmt"
"io/ioutil"
)
func main() {
// 1.定義需要複製的原始檔
srcFile := "/etc/hosts"
// 2.定義複製到目標檔案路徑
destFile := "./hosts"
// 3.對原始檔進行讀取資料
content, err := ioutil.ReadFile(srcFile)
if err != nil {
fmt.Printf("檔案讀取失敗: err = %s\n", err)
return
}
// 4.將讀取到的資料寫入目標檔案
err = ioutil.WriteFile(destFile, content, 0644)
if err != nil {
fmt.Printf("檔案寫入失敗, err=%v\n", err)
}
fmt.Printf("'%s'檔案複製完成\n", srcFile)
}
2.藉助io.Copy()
實現一個複製檔案函式
package main
import (
"fmt"
"io"
"os"
)
// CopyFile 複製檔案函式
func CopyFile(dstFile, srcFile string) (written int64, err error) {
// 以讀方式開啟原始檔
src, err := os.Open(srcFile)
if err != nil {
fmt.Printf("開啟%s檔案失敗, err = %v\n", srcFile, err)
return
}
defer src.Close()
// 以寫|建立的方式開啟目標檔案
dest, err := os.OpenFile(dstFile, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Printf("開啟%s檔案失敗, err = %v\n", dstFile, err)
return
}
defer dest.Close()
//呼叫io.Copy()複製內容檔案內容
return io.Copy(dest, src)
}
func main() {
_, err := CopyFile("./hosts", "/etc/hosts")
if err != nil {
fmt.Println("複製檔案失敗,err = ", err)
return
}
fmt.Println("複製完成")
}