go语言文件操作
Posted qhdsavoki
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言文件操作相关的知识,希望对你有一定的参考价值。
文件操作
字符串处理函数
字符串在开发中使用频率较高,我们经常需要对字符串进行拆分、判断等操作,可以借助Go标准库中的strings包快速达到处理字符串的目录。除Contains、Join、Trim、Replace等我们学过的字符串处理函数之外,以下函数也常常会被用到。
字符串分割
func Split(s, sep string) []string //功能:把s字符串按照sep分割,返回slice 参1:s,表示待拆分的字符串 参2:sep,表示分割符,该参数为string 类型 返回值:切片,存储拆分好的子串
示例代码:
fmt.Printf("%q ", strings.Split("a,b,c", ",")) fmt.Printf("%q ", strings.Split("a man a plan a canal panama", "a ")) fmt.Printf("%q ", strings.Split(" xyz ", "")) fmt.Printf("%q ", strings.Split("", "Bernardo O‘Higgins")) //运行结果: //["a" "b" "c"] //["" "man " "plan " "canal panama"] //[" " "x" "y" "z" " "] //[""]
按空格拆分字符串
func Fields(s string) []string //功能:去除s字符串的空格符,并且按照空格分割,返回slice 参1:s,表示待拆分的字符串 返回值:切片,存储拆分好的子串
示例代码:
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) //运行结果:Fields are: ["foo" "bar" "baz"]
判断字符串后缀
func HasSuffix(s, suffix string) bool 功能:判断s字符串是否有后缀子串suffix 参1:s,表示待判定字符串 参2:suffix,表示前缀子串 返回值:true or false
示例代码:
fmt.Printf("%v ", strings.HasSuffix("World Cup.png", ".png")) //运行结果:true
判断字符串前缀
func HasPrefix(s, prefix string) bool 功能:判断s字符串是否有前缀子串suffix 参1:s,表示待判定字符串 参2:prefix,表示前缀子串 返回值:true or false
示例代码:
fmt.Printf("%v ", strings.HasPrefix("World Cup.png", "world")) //运行结果:false
文件操作常用API
建立与打开文件
新建文件可以通过如下两个方法:
func Create(name string) (file *File, err Error) 根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666的文件,返回的文件对象是可读写的。
func main() { f, err := os.Create("C:/itcast/test.txt") if err != nil { fmt.Println("Create err:", err) return } defer f.Close() fmt.Println("create successful") }
通过如下两个方法来打开文件:
func Open(name string) (file *File, err Error)
func main() { f, err := os.Open("C:/itcast/test.txt") if err != nil { fmt.Println("open err: ", err) return } defer f.Close() _, err = f.WriteString("hello world") if err != nil { fmt.Println("WriteString err: ", err) return } fmt.Println("open successful") }
Open()是以只读权限打开文件名为name的文件,得到的文件指针file,只能用来对文件进行“读”操作。如果我们有“写”文件的需求,就需要借助Openfile函数来打开了。
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
OpenFile()可以选择打开name文件的读写权限。这个函数有三个默认参数:
参1:name,表示打开文件的路径。可使用相对路径 或 绝对路径
参2:flg,表示读写模式,常见的模式有:
O_RDONLY(只读模式), O_WRONLY(只写模式), O_RDWR(可读可写模式), O_APPEND(追加模式)。| O_CREATE (当有此参数,必须指定 参数3) 重要的是如果读取目录的话只能指定O_RDONLY模式!!!!
参3:perm,表权限取值范围(0-7),表示如下:
0:没有任何权限
1:执行权限(如果是可执行文件,是可以运行的)
2:写权限
3: 写权限与执行权限
4:读权限
5: 读权限与执行权限
6: 读权限与写权限
7: 读权限,写权限,执行权限
func main() { f, err := os.OpenFile("C:/itcast/test.txt", os.O_RDWR | os.O_CREATE, 0600) // 777--rwx rwx rwx if err != nil { fmt.Println("OpenFile err: ", err) return } defer f.Close() f.WriteString("hello world12345...") fmt.Println("open successful") }
关闭文件函数:
func (f *File) Close() error
写文件
1.按照字符串写:
func (file *File) WriteString(s string) (ret int, err Error) 写入string信息到文件
f.WriteString
返回实际写出的字节数
windows: 回车、换行。
Linux: 回车、换行。
2.指定位置写入
1)Seek(): 获取文件读写位置。 func (f *File) Seek(offset int64, whence int) (ret int64, err error) offset: 矢量。 正数,向文件末尾偏移。负数,向文件开头偏移 whence: 偏移的起始位置。 io.SeekStart : 文件起始位置。 io.SeekCurrent : 文件当前位置。 io.SeekEnd: 文件末尾位置。 返回值 ret: 从文件起始位置到,读写位置的偏移量。 2)WriteAt(): 在指定位置写入数据。, 通常搭配 Seek()用 func (f *File) WriteAt(b []byte, off int64) (n int, err error) b: 待写入的数据内容 off:写入的位置。(通常是 Seek函数的 返回值)
例子:
package main import ( "os" "fmt" "io" ) func main() { f, err := os.Create("./test.txt") if err != nil { fmt.Println("Create err:", err) return } defer f.Close() n, err := f.WriteString("hello world ") if err != nil { fmt.Println("WriteString err:", err) return } fmt.Println("n = ", n) //off, err := f.Seek(5, io.SeekStart) off, err := f.Seek(-5, io.SeekEnd) if err != nil { fmt.Println("Seek err:", err) return } fmt.Println("off:", off) n, err = f.WriteAt([]byte("1111"), off) if err != nil { fmt.Println("WriteAt err:", err) return } fmt.Println("write successful") }
3.按字节写--按字节读 :重要!!!!! ---- 按字节处理文件。既可以处理文本也可以处理二进制文件(.jpg/mp3/avi....)
func (file *File) Read(b []byte) (n int, err Error)
b: 用来存储读到的数据的 缓冲区。
返回n:实际读到的 字节数。
func (file *File) Write(b []byte) (n int, err Error)
b: 存储数据的缓冲区,其中的数据即将被写入文件。。
返回n:实际写出的 字节数。
1 func main01() { 2 f, err := os.OpenFile("test.txt", os.O_RDWR, 0600) 3 if err != nil { 4 fmt.Println("Open err:", err) 5 return 6 } 7 defer f.Close() 8 9 buf := make([]byte, 4096) // 4k 10 11 n, err := f.Read(buf) 12 if err != nil { 13 fmt.Println("Read err:", err) 14 return 15 } 16 fmt.Printf("read data:%s", buf[:n]) 17 } 18 19 func main02() { 20 f, err := os.OpenFile("test.txt", os.O_RDWR, 0600) 21 if err != nil { 22 fmt.Println("Open err:", err) 23 return 24 } 25 defer f.Close() 26 27 n, err := f.Write([]byte("AAA")) 28 if err != nil { 29 fmt.Println("Write err:", err) 30 return 31 } 32 fmt.Println("n = ", n) 33 }
读文件:bufio
按行读。----- 处理文本文件。 1) 获取一个 reader(自带缓冲区) func NewReader(rd io.Reader) *Reader rd: 成功打开的文件指针。 f 返回值:Reader (阅读器,自带缓冲区) 2)从 reader 的缓冲区中获取 指定数据 ReadBytes( ‘ ‘ ) func (b *Reader) ReadBytes(delim byte) ([]byte, error) delim :读取数据的拆分依据。 返回值:成功获取到的数据内容。 通常,会使用 for 来循环调用 ReadBytes, 一直读到 err == io.EOF 的时候,结束信息。代表文件读取完毕。
1 package main 2 3 import ( 4 "os" 5 "fmt" 6 "bufio" 7 "io" 8 ) 9 10 func main() { 11 f, err := os.Open("test.txt") 12 if err != nil { 13 fmt.Println("Open err:", err) 14 return 15 } 16 defer f.Close() 17 18 // 获取阅读器 reader, 自带缓冲区(用户缓冲)。 19 reader := bufio.NewReader(f) 20 21 for { // 循环读取文件, 当 err == io.EOF 结束循环 22 // 使用 带分割符的 函数,读取指定数据 ‘ ’获取一行 23 buf, err := reader.ReadBytes(‘ ‘) 24 // 成功读取到的一行数据 保存在 buf中 25 fmt.Printf("buf:%s", buf) 26 if err != nil && err == io.EOF { 27 break 28 } 29 } 30 fmt.Println("文件读取完毕") 31 }
读目录:
1) 打开目录 OpenFile func OpenFile(name string, flag int, perm FileMode) (*File, error) flag: 只能指定 O_RDONLY perm : os.ModeDir ---> 操作目录文件 返回: 操作目录文件的 指针 2) 读取目录项 Readdir func (f *File) Readdir(n int) ([]FileInfo, error) n:读取目录项的个数。 -1 表全部 返回值:每一个目录项 描述信息的(FileInfo) 切片 []FileInfo 切片 type FileInfo interface { Name() string // base name of the file Size() int64 // length in bytes for regular files; system-dependent for others 。。。 IsDir() bool // abbreviation for Mode().IsDir() 。。。 }
1 package main 2 3 import ( 4 "os" 5 "fmt" 6 ) 7 8 func main() { 9 var dir string 10 fmt.Print("请输入一个待判定的目录:") 11 fmt.Scan(&dir) 12 13 // 打开目录 14 f, err := os.OpenFile(dir, os.O_RDONLY, os.ModeDir) 15 if err != nil { 16 fmt.Println("OpenFile err:", err) 17 return 18 } 19 defer f.Close() 20 21 // 读取目录项 -- 将一个目录下的所有内容, 存入[]FileInfo 22 fileInfo, err := f.Readdir(-1) 23 if err != nil { 24 fmt.Println("Readdir err:", err) 25 return 26 } 27 28 // 依次取出目录项 29 for _, dirInfo := range fileInfo { 30 if dirInfo.IsDir() { 31 fmt.Printf("%s 是一个 目录 ", dirInfo.Name()) 32 } else { 33 fmt.Printf("%s is not 目录 ", dirInfo.Name()) 34 } 35 } 36 37 }
练习例子
大文件拷贝实现:
1. 只读打开文件 os.Open --> fr defer close() 2. 创建新文件 os.Create --> fw defer close() 3. for 循环安字节读取 fr 中的所有数据, 存入 buf 4. 读多少,写多少,将buf 中数据写入 fw 5. 判断 err == io.EOF 来确认读到文件末尾。
package main import ( "os" "fmt" "io" ) func main() { // 创建 待读取的文件,和 待写入的文件 f_r, err := os.Open("C:/itcast/01-结构体的定义和初始化.avi") if err != nil { fmt.Println("open err:", err) return } defer f_r.Close() f_w, err := os.Create("./test.avi") if err != nil { fmt.Println("Create err:", err) return } defer f_w.Close() buf := make([]byte, 4096) //创建缓冲区,存储读到的数据 // 循环从 f_r 对应文件中读取数据, for { n, err := f_r.Read(buf) if err == io.EOF { fmt.Println("读取文件完成") break } if err != nil { fmt.Println("Read err:", err) return } // 原封不动写到 f_w 文件中, 读多少,写多少 n, err = f_w.Write(buf[:n]) if err != nil { fmt.Println("Write err:", err) return } } os.OpenFile() }
练习1 初级练习
func main() { //从用户给出的目录中,找出所有的 .jpg 文件 var path string fmt.Scan(&path) f,err:=os.OpenFile(path,os.O_RDONLY,os.ModeDir) if err!=nil{ fmt.Println(err) return } fileinfo,err:=f.Readdir(-1) if err!=nil{ fmt.Println("err",err) return } for _,i:=range fileinfo{ if strings.HasSuffix(i.Name(),"jpg"){ fmt.Println(i.Name()) } }
练习2 中级练习
package main import ( "fmt" "os" "strings" "io" ) func copyMp3ToDir(fileName, path string) { pathName := path + "/" + fileName fr, err := os.Open(pathName) // 打开 源文件 if err != nil { fmt.Println("Open err:", err) return } defer fr.Close() fw, err :=os.Create("./" + fileName) // 打开拷贝的文件 if err != nil { fmt.Println("Create err:", err) return } defer fw.Close() // 创建一个用于read 存储数据的 buf buf := make([]byte, 4096) // 循环从 fr 中读取数据, 原封不动 写到 fw中 for { n, err := fr.Read(buf) if n == 0 { fmt.Println("文件拷贝完毕") break } if err != nil && err != io.EOF { fmt.Println("err:", err) } fw.Write(buf[:n]) // 读多少,写多少 } } func main() { // 请用户指定 目录 var path string fmt.Print("请输入目录位置:") fmt.Scan(&path) // 打开指定目录位置 dir_fp, err := os.OpenFile(path, os.O_RDONLY, os.ModeDir) if err != nil { fmt.Println("Openfile err:", err) return } defer dir_fp.Close() // 读取目录项 dirsInfo, err := dir_fp.Readdir(-1) if err != nil { fmt.Println("Readdir err:", err) return } // 从目录项[] 中提取每一个目录项 for _, dir := range dirsInfo { fileName := dir.Name() // 根据后缀名,筛选文件 if strings.HasSuffix(fileName, ".mp3") { // 将该文件 copy 至指定目录 copyMp3ToDir(fileName, path) //fmt.Println("mp3文件有:", fileName) } } }
//2.从用户给出的目录中,拷贝 .mp3文件到指定目录中。 args:=os.Args f1,err:=os.OpenFile(args[1],os.O_RDONLY,os.ModeDir) if err!=nil{ fmt.Println(err) return } fmt.Println(args[1],args[2]) fileinfo,err:=f1.Readdir(-1) if err!=nil { fmt.Println(err) } for _,name:=range fileinfo{ //fmt.Println(name) if strings.HasSuffix(name.Name(),".mp3"){ fmt.Println(name.Name()) copyfile(args[1]+"/"+name.Name(),args[2]+"/"+name.Name()) } } defer f1.Close() } func copyfile(dst,src string){ buf:=make([]byte,4096) f1, err := os.OpenFile(dst, os.O_RDONLY, 0666) if err != nil { fmt.Println(err) return } fw, err := os.Create(src) if err != nil { fmt.Println(err) return } for { n, err := f1.Read(buf) if err != nil || err ==io.EOF{ fmt.Println(err) break } fw.Write(buf[:n]) } defer fw.Close()
练习3 高级练习
1 package main 2 3 import ( 4 "os" 5 "fmt" 6 "strings" 7 "bufio" 8 "io" 9 ) 10 11 func countLove(fileName, path string) int { 12 // 打开文件,txt 13 f, err := os.Open(path + "/" + fileName) 14 if err != nil { 15 fmt.Println("Open err:", err) 16 return -1 17 } 18 defer f.Close() 19 20 // 1 创建 reader 21 reader := bufio.NewReader(f) 22 var counter int = 0 23 24 // for 循环 按行读取文件,--- this is a test for love --》[]string 25 for { 26 // 2 指定分隔符,按行提取数据 27 buf, err := reader.ReadBytes(‘ ‘) // buf中保存读到的一行数据 28 if err != nil && err == io.EOF { 29 break 30 } 31 if err != nil { 32 fmt.Println("ReadBytes err:", err) 33 return -1 34 } 35 // 将一行数据中的所有单词 拆分 36 words := strings.Fields(string(buf)) 37 for _, word := range words { 38 if word == "love" { 39 counter++ // 统计 个数。 40 } 41 } 42 } 43 fmt.Println("counter:", counter) 44 45 return counter 46 } 47 48 func main() { 49 50 // 测试统计 函数是否生效 51 //countLove("test.txt", "C:/itcast/test2") 52 53 // 请用户指定 目录 54 var path string 55 fmt.Print("请输入目录位置:") 56 fmt.Scan(&path) 57 58 // 打开指定目录位置 59 dir_fp, err := os.OpenFile(path, os.O_RDONLY, os.ModeDir) 60 if err != nil { 61 fmt.Println("Openfile err:", err) 62 return 63 } 64 defer dir_fp.Close() 65 66 // 统计目录下所有 txt 文件的 love 个数 67 var allLove int = 0 68 69 // 读取目录项 70 dirsInfo, err := dir_fp.Readdir(-1) 71 if err != nil { 72 fmt.Println("Readdir err:", err) 73 return 74 } 75 // 从目录项[] 中提取每一个目录项 76 for _, dir := range dirsInfo { 77 fileName := dir.Name() 78 // 根据后缀名,筛选文件 79 if strings.HasSuffix(fileName, ".txt") { 80 // 打开文件, 统计 该文件中有多少个 “love” 81 allLove += countLove(fileName, path) 82 } 83 } 84 fmt.Println("指定的目录中,一共包含 love 个数:", allLove) 85 }
1 package main 2 3 import ( 4 "os" 5 "fmt" 6 "strings" 7 "bufio" 8 "io" 9 ) 10 11 func main() { 12 //统计指定目录下,所有.txt文件中,“Love”这个单词 出现的次数。 13 args:=os.Args 14 fdir,err:=os.OpenFile(args[1],os.O_RDONLY,os.ModeDir) 15 if err!=nil{ 16 fmt.Println(err) 17 return 18 } 19 fileinof,err:=fdir.Readdir(-1) 20 var txt []string 21 for _,info:=range fileinof{ 22 23 if strings.HasSuffix(info.Name(),".txt"){ 24 fmt.Println(info.Name()) 25 txt=append(txt, info.Name()) 26 } 27 } 28 for _,v:=range txt{ 29 prisetxt("love","D:/111/"+v) 30 } 31 } 32 //func dir(){} 33 func prisetxt(s string,txt string){ 34 35 f1,err:=os.Open(txt) 36 if err!=nil{ 37 fmt.Println(err) 38 } 39 reader:=bufio.NewReader(f1) 40 //conster :=0 41 for { 42 bytess, err := reader.ReadBytes(‘ ‘) 43 fmt.Println(string(bytess)) 44 con:=strings.Split(string(bytess),"love") 45 fmt.Println(len(con)-1) 46 if err != nil || err == io.EOF { 47 fmt.Println(err) 48 break 49 } 50 51 } 52 defer f1.Close() 53 //fmt.Println(conster) 54 55 }
以上是关于go语言文件操作的主要内容,如果未能解决你的问题,请参考以下文章
[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础