這篇是在 stackoverflow 上看到的
覺得滿實用
在Golang要操作檔案有三種方法
第一種就是操作檔案的指標
跟php的fopen差不多
以下是第一段程式碼
package main
import (
"io"
"os"
)
func main() {
// open input file
fi, err := os.Open("input.txt")
if err != nil {
panic(err)
}
// close fi on exit and check for its returned error
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
// open output file
fo, err := os.Create("output.txt")
if err != nil {
panic(err)
}
// close fo on exit and check for its returned error
defer func() {
if err := fo.Close(); err != nil {
panic(err)
}
}()
// make a buffer to keep chunks that are read
buf := make([]byte, 1024)
for {
// read a chunk
n, err := fi.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
// write a chunk
if _, err := fo.Write(buf[:n]); err != nil {
panic(err)
}
}
}
第10行使用os.Open來開啟一個檔案
並返回該檔案的指標與錯誤訊息
每次開啟的檔案都要記得關閉
Golang有提供defer這個關鍵字
可以在最後執行某個function
而第22行使用os.Create來開啟一個檔案
跟os.Open一樣都是返回檔案的指標與錯誤訊息
這兩者有什麼差異呢?
其實os.Create跟os.Open都是呼叫同一個function
叫os.OpenFile(name string, flag int, perm FileMode) (*File, error)
差別就在於flag跟perm的參數不同
os.Open是單純的Read only
package main
import (
"bufio"
"io"
"os"
)
func main() {
// open input file
fi, err := os.Open("input.txt")
if err != nil {
panic(err)
}
// close fi on exit and check for its returned error
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
// make a read buffer
r := bufio.NewReader(fi)
// open output file
fo, err := os.Create("output.txt")
if err != nil {
panic(err)
}
// close fo on exit and check for its returned error
defer func() {
if err := fo.Close(); err != nil {
panic(err)
}
}()
// make a write buffer
w := bufio.NewWriter(fo)
// make a buffer to keep chunks that are read
buf := make([]byte, 1024)
for {
// read a chunk
n, err := r.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
// write a chunk
if _, err := w.Write(buf[:n]); err != nil {
panic(err)
}
}
if err = w.Flush(); err != nil {
panic(err)
}
}
乍看跟第一種好像差不多
但是bufio有提供更多方法來讀取/寫入檔案
像是他可以讀取一整行bufio.ScanLines
或是其他好用方法可參考文件
第三種程式如下
package main
import (
"io/ioutil"
)
func main() {
// read the whole file at once
b, err := ioutil.ReadFile("input.txt")
if err != nil {
panic(err)
}
// write the whole body at once
err = ioutil.WriteFile("output.txt", b, 0644)
if err != nil {
panic(err)
}
}
這種就非常簡短
適合新手使用
總結
我個人是使用第一種方式
因為我需要取得檔案指標來做其他事
不過要注意一點
若要重複使用檔案指標
就必須重置指標的位置
例如想取得檔案內容又想產生MD5
在取得內容之後
檔案指標是在檔案的結尾
所以要呼叫 f.Seek(0, 0)
來將指標移回開頭的位置