Seek
func (f *File) Seek(offset int64, whence int) (ret int64, err error)
官方注释:Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。
whence参数
// 0
// 1
// 2
具体使用方法
文件内容: 0123456789
func tSeek_1() {
f, err := os.OpenFile(``, 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。
还有一个函数,和该方法类似
func Truncate(name string, size int64) error
具体使用方法
func tTruncate_1() {
f, err := os.OpenFile(``, 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),继续写下一个文件。