目錄
- 示例1: 打開和關閉檔案
- 示例2: 打開檔案并讀取內容
- 示例3: 一次性讀取檔案
- 示例4: 帶緩沖的Reader讀檔案
- 示例5: 創建檔案并寫入內容
- 示例6: 寫檔案的四種方式
- 示例7: 把一個檔案內容寫入到另一個檔案
- 示例8:使用bufio獲取用戶輸入
- 示例9: 判斷檔案或目錄是否存在
- 示例10: 拷貝檔案、圖片音視頻
- 示例11: 遍歷目錄
- 遍歷目錄
- 僅遍歷目錄,忽略檔案
- 示例12: 修改檔案名
- 示例13:創建目錄
- 示例14:洗掉檔案
對于檔案,我們并不陌生,檔案是資料源(保存資料的地方)的一種,比如大家經常使用的word檔案,txt檔案,Excel檔案...等等都是檔案,檔案最主要的作用就是保存資料,它既可以保存一張圖片,也可以保存視頻,聲音......
檔案在程式中是以流的形式來操作的,

流:資料在資料源(檔案)和程式(記憶體)之間經歷的路徑
輸出流:資料從程式(記憶體)到資料源(檔案)的路徑
輸入流:資料從資料源(檔案)到程式(記憶體)的路徑
輸入與輸出都是相對于記憶體而言的,從記憶體向外流就是輸出,從外部向記憶體流就是輸入
在Go中,我們操作檔案的方法在os包中,會經常使用到os.File結構體 Go語言標準庫檔案



示例1: 打開和關閉檔案
package main
import (
"fmt"
"os"
)
func main() {
//打開檔案(/Users/xxx/Go/src/file.txt)
//概念說明:file的叫法
//1.file 叫 file物件
//2.file 叫 file指標
//3.file 叫 file檔案句柄
file, err := os.Open("/Users/itbsl/Go/src/file.txt")
if err != nil {
fmt.Println("檔案打開失敗,原因是:", err)
//os.Exit(0)
}
defer func() {
//檔案及時關閉
err = file.Close()
if err != nil {
fmt.Println("檔案關閉失敗,原因是", err)
}
}()
}
示例2: 打開檔案并讀取內容
使用Read()函式按照位元組讀
package main
import (
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("./test.txt")
if err != nil {
fmt.Printf("open file failed, err:%v\n", err)
return
}
defer func() {
err = file.Close()
if err != nil {
fmt.Printf("close file failed, err:%v\n", err)
}
}()
var content []byte
var tmp = make([]byte, 128)
for {
n, err := file.Read(tmp)
//為什么是tmp[:n]而不是tmp[:]?
//因為當讀取到最后一行的內容長度不足tmp的長度的時候
//新讀取的內容只會覆寫前半部分上次讀取到的tmp的內容,
//后半部分還是上一次讀取的內容,如果用tmp[:]就會導致
//后半部分久內容又會被重新賦值一次,這其實是錯誤的
content = append(content, tmp[:n]...)
if err == io.EOF {//讀到檔案末尾
break
}
}
fmt.Printf("讀取出來的內容為:\n")
fmt.Printf("%q\n", string(content))
}
示例3: 一次性讀取檔案
讀取檔案內容并顯示在終端,將檔案內容一次性讀取到終端,適用于檔案不大的情況,
package main
import (
"fmt"
"io/ioutil"
)
func main() {
//打開檔案,檔案路徑相對于GOPATH開始,或者寫全路徑(/Users/xxx/Go/src/file.txt)
file, err := ioutil.ReadFile("src/file.txt")
if err != nil {
fmt.Println("檔案打開失敗,原因是:", err)
}
fmt.Printf("%s", string(file))
}
示例4: 帶緩沖的Reader讀檔案
讀取檔案的內容并顯示在終端(帶緩沖區的方式),使用os.Open, file.Close,bufio.NewReader,reader.ReadString函式和方法,適合讀取大檔案
1.使用ReadBytes方法
代碼1:
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
)
func main() {
file, err := os.Open("./test.txt")
if err != nil {
log.Fatalf("open file failed, err: %v\n", err)
}
defer func() {
err = file.Close()
if err != nil {
log.Fatalf("close file failed, err: %v\n", err)
}
}()
//定義變數result用來存盤讀取結果
var result string
//創建一個帶有緩沖區的reader
reader := bufio.NewReader(file)
for {
buf, err := reader.ReadBytes('\n')
if err != nil && err == io.EOF { //EOF代表檔案的末尾
//注意:為什么要判斷err是否等于io.EOF?
//因為存在這種情況,檔案有內容的最后那一行尾部沒有換行
//當使用ReadBytes或者ReadString方法按照'\n'換行讀取時,讀到尾部沒有換行的這種情況時就會報io.EOF錯誤
//此時buf是讀取到了內容的,如果忽略掉了,那么最終的讀取結果會少了最后一行的內容
result += string(buf)
break
}
result += string(buf)
}
fmt.Println(result)
}
代碼2:
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
)
func main() {
file, err := os.Open("./test.txt")
if err != nil {
log.Fatalf("open file failed, err: %v\n", err)
}
defer func() {
err = file.Close()
if err != nil {
log.Fatalf("close file failed, err: %v\n", err)
}
}()
//定義變數result用來存盤讀取結果
var result string
//創建一個帶有緩沖區的reader
reader := bufio.NewReader(file)
for {
buf, err := reader.ReadBytes('\n')
if err != nil {
if err == io.EOF { //EOF代表檔案的末尾
//注意:為什么要判斷err是否等于io.EOF?
//因為存在這種情況,檔案有內容的最后那一行尾部沒有換行
//當使用ReadBytes或者ReadString方法按照'\n'換行讀取時,讀到尾部沒有換行的這種情況時就會報io.EOF錯誤
//此時buf是讀取到了內容的,如果忽略掉了,那么最終的讀取結果會少了最后一行的內容
result += string(buf)
break
} else {
log.Fatalf("ReadBytes failed, err: %v\n", err)
}
}
result += string(buf)
}
fmt.Println(result)
}
2.ReadString方法
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
//打開檔案
file, err := os.Open("./files/test.txt")
if err != nil {
fmt.Println("檔案打開失敗,原因是:", err)
return
}
//當函式退出時,要及時的關閉file
defer func() {
//檔案及時關閉
err = file.Close()
if err != nil {
fmt.Println("檔案關閉失敗,原因是", err)
}
}()
//創建一個 *Reader,是帶緩沖的
reader := bufio.NewReader(file)
var result string
//回圈讀取檔案內容
for {
str, err := reader.ReadString('\n') //讀到一個換行就結束
result += str
if err == io.EOF {//io.EOF代表檔案的末尾
//注意:如果檔案最后一行文字沒有換行,則會一直讀取到檔案末尾,
//所以即使是判斷讀到了檔案末尾,也要把讀取的內容輸出一下
break
}
}
fmt.Println(result)
}
示例5: 創建檔案并寫入內容

第二個引數:檔案代開模式(可以組合);第三個引數:權限控制(如0755)

package main
import (
"fmt"
"os"
)
func main() {
//1.創建檔案file.txt
file, err := os.OpenFile("src/file.txt", os.O_WRONLY | os.O_CREATE, 0755)
if err != nil {
fmt.Println("檔案打開/創建失敗,原因是:", err)
return
}
defer func() {
err = file.Close()
if err != nil {
fmt.Println("檔案關閉失敗,原因是:", err)
}
}()
//寫入資料
var str = "暗黑西游獅駝嶺,斗戰勝佛孫悟空,\n"
for i := 0; i < 5; i++ {
file.WriteString(str)
}
}
示例6: 寫檔案的四種方式
1.使用WriteAt()搭配Seek()方法實作寫檔案功能
package main
import (
"io"
"log"
"os"
)
func main() {
file, err := os.OpenFile("./test.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
log.Fatalf("open file failed, err: %v\n", err)
}
defer func() {
err = file.Close()
if err != nil {
log.Fatalf("close file failed, err: %v\n", err)
}
}()
//Seek(): 修改檔案的讀寫指標位置.
//引數1: 偏移量. 正:向檔案尾部偏移, 負:向檔案頭部偏移
//引數2: 偏移起始位置
// io.SeekStart: 檔案起始位置
// io.SeekCurrent: 檔案當前位置
// io.SeekEnd: 檔案結尾位置
//回傳值:表示從檔案起始位置,到當前檔案讀寫指標位置的偏移量,
//WriteAt(): 在檔案指定偏移位置,寫入[]byte,通常搭配Seek()
//引數1: 待寫入的資料
//引數2: 偏移量
//回傳: 實際寫出的位元組數
for i := 0; i < 5; i++ {
offset, _ := file.Seek(-3, io.SeekEnd)
_, _ = file.WriteAt([]byte("你好"), offset)
}
}
注意: 由于使用的OpenFile函式打開的檔案,所以在選擇打開模式的時候不能選擇os.O_APPEND模式,因為該模式表示的是在檔案末尾追加,這與WriteAt在指定的位置寫是想沖突的,雖然我在測驗的時候加上os.O_APPEND模式并沒有報錯,但是代碼執行完之后發現,想要寫入的內容并沒有真正的寫入到檔案中,
寫入前

寫入后

2.一次性寫檔案
package main
import (
"io/ioutil"
"log"
)
func main() {
str := "hello樹先生"
//如果檔案已存在,則會清空原來的內容,寫入新內容,如果檔案不存在,則會創建檔案并寫入內容
err := ioutil.WriteFile("./test.txt", []byte(str), 0755)
if err != nil {
log.Fatalf("寫入檔案錯誤,錯誤為:%v\n", err)
}
}
3.使用帶緩沖的方式寫檔案
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
//1.創建檔案file.txt
file, err := os.OpenFile("src/file.txt", os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0755)
defer func() {
err = file.Close()
if err != nil {
fmt.Println("檔案關閉失敗,原因是:", err)
}
}()
if err != nil {
fmt.Println("檔案創建失敗,原因是:", err)
return
}
//寫入資料
var str = "你好,世界\n"
//寫入時,使用帶快取的*Writer
writer := bufio.NewWriter(file)
for i := 0; i < 5; i++ {
writer.WriteString(str)
}
//因為writer是帶快取的,因此在呼叫writeString方法時,其實內容是先寫入到快取
//因此需要呼叫Flush方法,將快取資料寫入到檔案中,否則檔案中會丟失資料
writer.Flush()
}
示例7: 把一個檔案內容寫入到另一個檔案
package main
import (
"fmt"
"io/ioutil"
)
func main() {
//打開檔案,檔案路徑相對于GOPATH開始,或者寫全路徑(/Users/xxx/Go/src/file.txt)
data, err := ioutil.ReadFile("src/1.txt")
if err != nil {
fmt.Println("檔案打開失敗,原因是:", err)
}
err = ioutil.WriteFile("src/2.txt", data, 0755)
if err != nil {
fmt.Println("檔案寫入失敗,原因是:", err)
}
}
示例8:使用bufio獲取用戶輸入
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
var s string
var reader = bufio.NewReader(os.Stdin)
s, _ = reader.ReadString('\n')
fmt.Printf("讀取到的內容為:%s\n", s)
}
示例9: 判斷檔案或目錄是否存在
Go判斷檔案或檔案夾是否存在的方法為使用os.Stat()函式回傳的錯誤值進行判斷:
(1)如果回傳的錯誤為nil,說明檔案或檔案夾存在
(2)如果回傳的型別使用os.IsNotExist()判斷為true,說明檔案或檔案夾不存在
(3)如果回傳的錯誤為其它型別,則不確定是否存在
package main
import (
"fmt"
"os"
)
func main() {
isExist, err := isFileExists("src/sfile.txt")
if err != nil {
fmt.Println("發生錯誤:", err)
}
if isExist {
fmt.Println("存在")
} else {
fmt.Println("不存在")
}
}
//判斷檔案或者目錄是否存在
func isFileExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
示例10: 拷貝檔案、圖片音視頻
io.Copy方法
package main
import (
"fmt"
"io"
"os"
)
func CopyFile(srcFileName string, dstFileName string) (int64, error) {
//源檔案處理
srcFile, err := os.Open(srcFileName)
defer func() {
err = srcFile.Close()
if err != nil {
fmt.Println("源檔案關閉失敗,原因是:", err)
}
}()
if err != nil {
fmt.Println("源檔案打開失敗,原因是:", err)
return 0, err
}
//目標檔案處理
dstFile, err := os.OpenFile(dstFileName, os.O_CREATE | os.O_WRONLY, 0755)
defer func() {
err = dstFile.Close()
if err != nil {
fmt.Println("目標檔案關閉失敗,原因是:", err)
}
}()
if err != nil {
fmt.Println("目標檔案打開失敗,原因是:", err)
return 0, err
}
return io.Copy(dstFile, srcFile)
}
func main() {
result, err := CopyFile("src/dst.jpeg", "src/哈哈.jpeg")
if err == nil {
fmt.Println("拷貝成功!拷貝的位元組數為: ", result)
}
}
對于大檔案,我們還可以采用下面的方式
package main
import (
"io"
"log"
"os"
)
func CopyFile(srcFileName string, dstFileName string) {
//打開源檔案
srcFile, err := os.Open(srcFileName)
if err != nil {
log.Fatalf("源檔案讀取失敗,原因是:%v\n", err)
}
defer func() {
err = srcFile.Close()
if err != nil {
log.Fatalf("源檔案關閉失敗,原因是:%v\n", err)
}
}()
//創建目標檔案,稍后會向這個目標檔案寫入拷貝內容
distFile, err := os.Create(dstFileName)
if err != nil {
log.Fatalf("目標檔案創建失敗,原因是:%v\n", err)
}
defer func() {
err = distFile.Close()
if err != nil {
log.Fatalf("目標檔案關閉失敗,原因是:%v\n", err)
}
}()
//定義指定長度的位元組切片,每次最多讀取指定長度
var tmp = make([]byte, 1024*4)
//回圈讀取并寫入
for {
n, err := srcFile.Read(tmp)
n, _ = distFile.Write(tmp[:n])
if err != nil {
if err == io.EOF {//讀到了檔案末尾,并且寫入完畢,任務完成回傳(關閉檔案的操作由defer來完成)
return
} else {
log.Fatalf("拷貝程序中發生錯誤,錯誤原因為:%v\n", err)
}
}
}
}
func main() {
CopyFile("./worm.mp4", "./dist.mp4")
}
示例11: 遍歷目錄
遍歷目錄
package main
//我們讀寫的檔案一般存放于目錄中.因此,有時需要指定到某一個目錄下,根據目錄存盤的狀況
//再進行檔案的特定操作.接下來我們看看目錄的基本操作方法.
import (
"fmt"
"log"
"os"
)
//打開目錄
//打開目錄我們也使用OpenFile函式,但要指定不同的引數來通知系統,要打開的是一個目錄檔案.
//func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
//引數1: name,表示要打開的目錄名稱.使用絕對路徑較多
//引數2: flag,表示打開檔案的讀寫模式
//引數3: perm,表示打開權限.但對于目錄來說有所不同,通常傳os.ModeDir.
//回傳值:由于是操作目錄,所以file是指向目錄的檔案指標.err中保存錯誤資訊
//讀目錄內容
//這與讀檔案有所不同.目錄中存放的是檔案名和子目錄名.所以使用Readdir函式
//func (f *File) Readdir(n int) (fi []FileInfo, err error)
//如果n>0,Readdir函式會回傳一個最多n個成員的切片,這時,如果Readdir回傳一個空切片,
//它會回傳一個非nil的錯誤說明原因,如果到達了目錄f的結尾,回傳值err會是io.EOF,
//
//如果n<=0,Readdir函式回傳目錄中剩余所有檔案物件的FileInfo構成的切片,
//此時,如果Readdir呼叫成功(讀取所有內容直到結尾),它會回傳該切片和nil的錯誤值,
//如果在到達結尾前遇到錯誤,會回傳之前成功讀取的FileInfo構成的切片和該錯誤,
func main() {
//不推薦,因為通過查看ioutil.ReadDir()函式可知,官方使用的是os.Open()函式打開的目錄
//file, err := os.OpenFile("./dir", os.O_RDWR, os.ModeDir)
file, err := os.Open("./dir")
if err != nil {
log.Fatalf("檔案打開失敗,原因是:%v\n", err)
}
defer func() {
err = file.Close()
if err != nil {
log.Fatalf("檔案關閉失敗,原因是:%v\n", err)
}
}()
//Readdir方法回傳一個FileInfo介面型別的切片和一個error型別的錯誤
infos, err := file.Readdir(-1)
for _, info := range infos {
fmt.Printf("%v, %v\n", info.Name(), info.IsDir())
}
}
僅遍歷目錄,忽略檔案
方法1:使用os包
package main
import (
"fmt"
"os"
)
var dirNames = make([]string, 0, 50)
var pathSeparator = string(os.PathSeparator)
func traverseDir(filePath string) error {
file, err := os.Open(filePath)
if err != nil {
return err
}
fileInfo, err := file.Readdir(0)
if err != nil {
return err
}
for _, value := range fileInfo {
if value.IsDir() {
dirNames = append(dirNames, value.Name())
err = traverseDir(filePath+pathSeparator+value.Name())
if err != nil {
return err
}
}
}
return err
}
func main() {
var filePath = "./dir"
err := traverseDir(filePath)
if err != nil {
fmt.Println(err)
}
fmt.Println(dirNames)
}
方法2:使用ioutil包
package main
import (
"fmt"
"io/ioutil"
"os"
)
var dirNames = make([]string, 0, 50)
var pathSeparator = string(os.PathSeparator)
func traverseDir(filePath string) error {
fileInfos, err := ioutil.ReadDir(filePath)
if err != nil {
return err
}
for _, fileInfo :=range fileInfos {
if fileInfo.IsDir() {
dirNames = append(dirNames, fileInfo.Name())
err = traverseDir(filePath+pathSeparator+fileInfo.Name())
if err != nil {
return err
}
}
}
return err
}
func main() {
var filePath = "./dir"
err := traverseDir(filePath)
if err != nil {
fmt.Println(err)
}
fmt.Println(dirNames)
}
示例12: 修改檔案名
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
var pathSeparator = string(os.PathSeparator)
//重命名檔案
func renameFileName(filePath string, old string, new string) error {
files, err := ioutil.ReadDir(filePath)
if err != nil {
return err
}
for _, fileInfo := range files {
if !fileInfo.IsDir() {
err = os.Rename(filePath + pathSeparator + fileInfo.Name(),
filePath + pathSeparator + strings.Replace(fileInfo.Name(), old, new, -1),
)
if err != nil {
return err
}
}
}
return err
}
func main() {
var filePath = "./dir"
err := renameFileName(filePath, "f", "kkk")
if err != nil {
fmt.Printf("錯誤: %v\n", err)
}
}
示例13:創建目錄
package main
import (
"fmt"
"os"
)
func main() {
//Mkdir使用指定的權限和名稱創建一個目錄,如果出錯,會回傳*PathError底層型別的錯誤,
err := os.Mkdir("./foo", 0755)
if os.IsExist(err) {
fmt.Println("目錄已存在")
return
}
//MkdirAll使用指定的權限和名稱創建一個目錄,包括任何必要的上級目錄,并回傳nil,否則回傳錯誤,
//權限位perm會應用在每一個被本函式創建的目錄上,如果path指定了一個已經存在的目錄,MkdirAll不做任何操作并回傳nil,
err = os.MkdirAll("./foo/bar", 0755)
if err != nil {
fmt.Printf("%v\n", err)
return
}
}
示例14:洗掉檔案
package main
import (
"fmt"
"os"
)
func main() {
//Remove洗掉name指定的檔案或目錄,如果出錯,會回傳*PathError底層型別的錯誤,
//該方法不能洗掉非空目錄,如果想洗掉目錄以及目錄下的所有檔案,可以使用RemoveAll
err := os.Remove("./def")
if os.IsNotExist(err) {
fmt.Println("您要洗掉的檔案或目錄不存在")
return
}
if err != nil {
fmt.Println(err)
}
//RemoveAll洗掉path指定的檔案,或目錄及它包含的任何下級物件,
//它會嘗試洗掉所有東西,除非遇到錯誤并回傳,
//如果path指定的物件不存在,RemoveAll會回傳nil而不回傳錯誤,
err = os.RemoveAll("./def")
if err != nil {
fmt.Println(err)
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/6567.html
標籤:Go
