Golang語言檔案操作快速入門篇

尹正杰發表於2024-08-01

                                              作者:尹正傑

版權宣告:原創作品,謝絕轉載!否則將追究法律責任。

目錄
  • 一.檔案的讀取操作
    • 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("複製完成")
}

相關文章