Go语言文件处理

avatar 2020年6月7日22:29:12 评论 974 次浏览

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()//刷新缓存写入到文件中
}

如果文件已存在就会报错“文件错误 open golang-learn/index5.html: file exists”。到这里文件的操作基本说完了,后期有机会会加入一些更多的文件内容,没有了,看一些其他的吧,,,,,

avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: