Go语言中的文件处理,重点在于文件而非目录或者通用的文件系统,特别是如何读写标准格式(如 XML 和 JSON 格式)的文件以及自定义的纯文本和二进制格式文件。
Go语言的所有特性,现在我们可以灵活地使用 Go语言提供的所有工具。我们会充分利用这种灵活性并利用闭包来避免重复性的代码,同时在某些情况下充分利用 Go语言对面向对象的支持,特别是对为函数添加方法的支持。
看下面的例子,通过open打开一个文件,默认打开的文件是指针,我们需要通过读取打开文件的内容,才可以看到文件中具体是什么。
package main import ( "fmt" "os" ) func main() { //fmt.Println(os.Getwd()) //查看当我文件路径 path := "golang-learn/README.md" content , err := os.Open(path) if err != nil { //判断文件是否存在,如果不存在返回错误信息 fmt.Println("文件错误",err) } fmt.Println("www.wulaoer.org",content) }
打印结果
www.wulaoer.org &{0xc000064180}
下面使用NewReader函数读取文件内容,如果文件内容比较多,就需要循环读取,直到文件文件读取完,结束,不过默认NewReader函数每次读取的缓存是4096,如果缓存过大会影响服务的整体性能。
package main import ( "bufio" "fmt" "io" "os" ) func main() { //fmt.Println(os.Getwd()) path := "golang-learn/README.md" file, err := os.Open(path) if err != nil { fmt.Printf("文件错误") } defer file.Close() //打开文件后一定要记得关闭 read := bufio.NewReader(file) // 如果文件内容比较大可以循环读取,默认换成为4096 for { str,err := read.ReadString('\n') //读到换行就结束,如果读取的文件中含有换行就不能完整读取了。 //str = strings.TrimSpace(str)//如果文件中有换行,就需要再判断之前打印即可,这样就能读取整个文件内容 //fmt.Println(str) if err == io.EOF { break //结束退出 } fmt.Print(str) } }
打印结果
# golang-learn 记录学习golang的知识点 可以看看www.wulaoer.org
这里需要注意,如果文件中有空行,在使用ReadString('\n') 的时候就会在读取到空行的时候结束文件,其实在这个空行后还是有文件内容的,所以在这个时候不能判断文件是否结尾。如果文件比较小,可以使用ioutil读取,ioutil和open的区别是ioutil返回的是byte,需要进行转换一下方可。
package main import ( "fmt" "io/ioutil" ) func main() { //fmt.Println(os.Getwd()) path := "golang-learn/README.md" content, err := ioutil.ReadFile(path) //ioutil.ReadFile中已经封存了Open和Close,所以不需要Close文件 if err != nil { fmt.Println("文件错误",err) } //fmt.Printf("%v",content) fmt.Printf(string(content))//读取的内容是[]byte类型,所以需要string转换一下 }
打印结果
# golang-learn 记录学习golang的知识点 可以看看www.wulaoer.org
golang写入操作
写操作需要先拥有文件的读写权限,可以给文件定义权限,然后打开文件,在再文件中进行写入操作,写入操作又以下四种,第一种是在文件底部追加,第二种是覆盖现有文件内容,第三种是在文件制定位置插入,第四种是对没有的文件进行创建并写入操作,下面针对以上四种情况分别举例说明:
第一种在文件底部进行追加写入,这时我们需要用到文件的读写权限,或者文件的写权限,在golang中文件的读写模式用到O_RDWR,写模式是O_APPEND,
package main import ( "bufio" "fmt" "io" "os" ) func main() { //fmt.Println(os.Getwd()) path := "golang-learn/README.md" content, err := os.OpenFile(path,os.O_RDWR | os.O_APPEND, 0655) if err != nil { fmt.Println("文件错误",err) return } defer content.Close() str := "hello golang www.wulaoer.org \r\n" write := bufio.NewWriter(content) //for i := 0; i < 5; i++ { // write.WriteString(str) //} write.WriteString(str) write.Flush()//刷新缓存写入到文件中 con, err := os.Open(path) defer con.Close() reader := bufio.NewReader(con) for { strs,err := reader.ReadString('\n') if err == io.EOF { break } fmt.Print(strs) } }
在OpenFile中path是路径,后面跟的是打开模式,最后就是操作,最后的0655是定义的文件的权限,在文件操作中golang有以下几种操作方式:
const ( // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified. O_RDONLY int = syscall.O_RDONLY // open the file read-only.只读模式 O_WRONLY int = syscall.O_WRONLY // open the file write-only.只写模式 O_RDWR int = syscall.O_RDWR // open the file read-write.读写模式 // The remaining values may be or'ed in to control behavior. O_APPEND int = syscall.O_APPEND // append data to the file when writing.写入时将数据附加到文件中。 O_CREATE int = syscall.O_CREAT // create a new file if none exists.如果不存在文件,请创建新文件。 O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist. O_SYNC int = syscall.O_SYNC // open for synchronous I/O.为同步I/O打开。 O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.打开时截断常规可写文件 )
前面三种模式在操作文件时必须使用其中的一种,后面五种是对文件操作的控制行文,上面的例子中使用到了文件的追加,追加只能在文件结尾追加。那么覆盖文件就需要把原文件内容清理,然后在写入新的内容,这样就相当于覆盖了,看下面的例子:
package main import ( "bufio" "fmt" "os" ) func main() { //fmt.Println(os.Getwd()) path := "golang-learn/index4.html" content, err := os.OpenFile(path,os.O_WRONLY | os.O_TRUNC, 0655) //content, err := os.OpenFile(path,os.O_RDWR | os.O_TRUNC | os.O_CREATE, 0655)//两者都有覆盖的意思 if err != nil { fmt.Println("文件错误",err) return } defer content.Close() str := "hello golang www.wulaoer.org \r\n" write := bufio.NewWriter(content) write.WriteString(str) write.Flush()//刷新缓存写入到文件中 }
两者写意思相同,只是在打开模式不一样,不用区别对待,文件的操作一定要给予一定的权限,后面权限的四位中的三位655分别代表用户权限,组权限,其他权限,在写入时必须有写入权限。但是如果需要在文件的指定位置写入,又该如何写入呢?看下面的代码?
package main import ( "fmt" "io" "os" ) func main() { //fmt.Println(os.Getwd()) path := "golang-learn/index.html" srcfile,err := os.OpenFile(path,os.O_RDWR,0644) if err != nil { fmt.Println("open file filed %v",err) return } tmpfile,err := os.OpenFile("./123.tmp",os.O_CREATE | os.O_WRONLY | os.O_TRUNC,0644) if err != nil { fmt.Printf("open file filed %v",err) return } var b [10]byte //定义文件的需要插入的定位符 n,err := srcfile.Read(b[:]) if err != nil { fmt.Printf("read file failed,err:%v\n",err) return } tmpfile.Write(b[:n]) tmpfile.WriteString("www.wulaoer.org") var x [1024]byte //这里的定义是每次读取数据的大小 for { n,err := srcfile.Read(x[:]) if err == io.EOF { tmpfile.Write(x[:n]) break } if err != nil { fmt.Printf("read from file failed,err:%v\n",err) return } tmpfile.Write(x[:n]) } tmpfile.Close() srcfile.Close() ok := os.Rename("./123.tmp",path)//把临时文件名修改成原文件名 if ok == nil { fmt.Printf(" sucnss") } else { fmt.Printf("error") } }
这里使用的占位符的方式插入,如果插入的文件比较大,在插入时就需要计算一下占位符的问题,这个这里就先不叙述了,后期有时间会对这个问题单独一篇文章说明,下面看第四个问题如果对于不存在的文件如何写入呢?需要直接创建,然后在写入,如下:
package main import ( "bufio" "fmt" "os" ) func main() { //fmt.Println(os.Getwd()) path := "golang-learn/index4.html" content, err := os.OpenFile(path,os.O_WRONLY | os.O_CREATE | os.O_EXCL, 0655) //创建新文件并插入内容 if err != nil { fmt.Println("文件错误",err) return } defer content.Close() str := "hello golang www.wulaoer.org \r\n" write := bufio.NewWriter(content) write.WriteString(str) write.Flush()//刷新缓存写入到文件中 }
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏