Seek

func (f *File) Seek(offset int64, whence int) (ret int64, err error)

官方注释:Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。

whence参数

io.SeekStart // 0
io.SeekCurrent // 1
io.SeekEnd // 2

具体使用方法

1.txt 文件内容: 0123456789

func tSeek_1() {
	f, err := os.OpenFile(`1.txt`, os.O_RDWR, os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	end, err := f.Seek(0, io.SeekEnd)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("end: ", end) // end: 10
	fs, err := f.Stat()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("size: ", fs.Size()) 

	// 都是含前不含后的概念
	// offset是从0开始的, 可以比当前的文件内容长度大,多出的部分会用空(0)来代替
	start, err := f.Seek(12, io.SeekStart)
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Println("start: ", start)
	_, err = f.WriteString("a")
	if err != nil {
		log.Fatal(err)
	}
	b := make([]byte, 102)
	n, err := f.Read(b)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(b[:n]) // [48 49 50 51 52 53 54 55 56 57 0 0 97]
}

Truncate

func (f *File) Truncate(size int64) error

官方注释:Truncate改变文件的大小,它不会改变I/O的当前位置。 如果截断文件,多出的部分就会被丢弃。如果出错,错误底层类型是*PathError。

还有一个os.Truncate函数,和该方法类似

func Truncate(name string, size int64) error

具体使用方法

func tTruncate_1() {
	f, err := os.OpenFile(`1.txt`, os.O_RDWR, os.ModePerm)
	if err != nil {
		log.Fatal(err)
	}

	s, err := f.Seek(4, io.SeekStart)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(s)

	// Truncate方法截取长度为size,即删除后面的内容,不管当前的偏移量在哪儿,都是从头开始截取
	// 但是其不会影响当前的偏移量
	err = f.Truncate(1)
	if err != nil {
		log.Fatal(err)
	}

	_, err = f.WriteString("32")
	if err != nil {
		log.Fatal(err)
	}
	b := make([]byte, 102)
	n, err := f.Read(b)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(b[:n])
}

简单谈下我的使用场景

我现在有一个自定义格式的文件(包含多文件),不断的写头写体进去,现在有可能头已经写好了,并标明了体的大小了,但是在写体的时候出错了,这时候需要将file回退到未写该文件的状态,即抹除掉刚刚写的头和一部分体。
我的做法是:在写之前,先Seek当前的偏移量(SeekEnd),若出错,先Truncate截取到刚刚记录的(SeekEnd)量,然后再Seek到(SeekEnd),继续写下一个文件。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐