目录
- Seeker接口
- 一、Seeker接口简介
- 二、Seeker接口的应用场景
- 三、Seeker接口的使用示例
- 四、断点续传
Seeker接口
在现代软件开发中,高效的输入输出(I/O)操作是提高程序性能的关键之一。特别是在处理大量数据时,I/O操作的效率直接影响到应用程序的响应速度和用户体验。Go语言标准库中的io包提供了一系列接口,用于处理各种I/O操作,其中Seeker接口在处理大文件或需要随机访问的场景中非常有用。本文将结合具体案例,详细介绍Go语言中io包的Seeker接口的用法。
一、Seeker接口简介
设置光标的位置,通过设置的光标位置来读写文件
用于在数据流中将光标跳转到指定的位置Seeker接口表示一个定位器,可以用来定位文件或流的位置。其定义如下:
type Seeker interface { Seek(offset int64, whence int) (int64, error) }
Seek方法接受两个参数:
offset:相对位移量,表示从起始位置移动的字节数。
whence:起始位置,可以是以下三个常量之一:
- io.SeekStart:从文件开头开始计算偏移量。
- io.SeekCurrent:从当前文件指针位置开始计算偏移量。
- io.SeekEnd:从文件末尾开始计算偏移量(此时offset通常为负数,表示向前移动)。
Seek方法返回两个值:
- position:移动后的文件指针位置(相对于文件开头的字节数)。
- err:可能发生的错误。
二、Seeker接口的应用场景
随机访问大文件:对于非常大的文件,通过Seek方法可以直接定位到文件的任意位置进行读写操作,而不需要从头开始遍历文件。
断点续传:在网络传输或文件复制等场景中,如果传输过程中断,可以通过Seek方法定位到上次传输的断点,继续传输剩余的数据。
日志文件分析:对于包含多条记录的日志文件,可以通过Seek方法快速定位到特定记录的位置,进行日志分析或错误排查。
三、Seeker接口的使用示例
以下是一个结合具体案例的示例代码,展示了如何使用Seeker接口来定位文件位置并进行读写操作。
File对象实现了Seeker接口
file对象可以直接调用Seek方法
我们先看下a.txt文件
代码示例:
package main import ( "fmt" "io" 编程客栈 "os" ) func main() { // 读取文件 file, _ := os.OpenFile("F:\\goworks\\src\\jingtian\\yufa\\io操作\\a.txt", os.O_RdwR, os.ModePerm) // defer close defer file.Close() // 测试seek // 相对开始位置。io.SeekStart // 相对于文件末尾, io.SeekEnd // func (f *File) Seek(offset int64, whence int) (ret int64, err error) //相对于开始位置,光标偏移两个字节 file.Seek(2, io.SeekStart) //创建一个字节的buffejavascriptr buf := []byte{0} file.Read(buf) fmt.Println(string(buf)) // n //Read读了一个字节, 光标现在在3这个位置 // 相对于当前位置 file.Seek(3, io.SeekCurrent) file.Read(buf) fmt.Println(string(buf)) // a // 在结尾追加内容 //相对于结束位置偏移0,光标就设在了结束位置 file.Seek(0, io.SeekEnd) //写入内容 file.WriteString("hahahaha") }
运行
再看下a.txt,可见在末尾写入了我们指定的内容
四、断点续传
断点续传是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传或者下载未完成的部分,而没有必要从头开始上传或者下载。
go语言实现断点续传的思路:
使用临时文件记录中断位置.
1.文件上传时,先创建上传一个新的文件
2.创建记录中断位置的临时文件,需要记住上一次传递了多少数据、temp.txt
3.设置文件读写偏移量,如果被暂停或javascript者中断了,我们就可以读取这个temp.txt的记录,恢复上传
4.上传完成后,删除临时文件
package main import ( "fmt" "io" "os" "strconv" ) // 断点续传 func main() { // 传输源文件地址 srcFile := "D:\\downloads\\mingw.7z" // 传输的目标位置 destFile := "F:\\goworks\\src\\jingtian\\yufa\\io操作\\server\\mingw.7z" // 临时记录文件 tempFile := "F:\\goworks\\src\\jingtian\\yufa\\io操作\\temp.txt" // 创建对应的file对象,连接起来 file1, _ := os.Open(srcFile) file2, _ := os.OpenFile(destFile, os.O_CREATE|os.O_RDWR, os.ModePerm) file3, _ := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, os.ModePerm) defer file1.Close() defer file2.Close() fmt.Println("file1/2/3 文件连接建立完毕") // 1、读取temp.txt file3.Seek(0, io.SeekStart) buf := make([]byte, 1024) n, _ := file3.Read(buf) //这里的n是读取file3中的字符的个数,比如1024,得到的n是4.所以要借助string转 //查看返回的n的数据类型 fmt.Printf("查看n的数据类型%Tphp\n", n) fmt.Println("n的值为", n) // 2、先转换成string,然后再转换成数字。 countStr := string(buf[:n]) count, _ := strconv.ParseInt(countStr, 10, 64) fmt.Println("temp.txt中记录的值为:", count) // 5120 // 3、设置读写的偏移量,offset是int64数据类型 file1.androidSeek(count, io.SeekStart) file2.Seek(count, io.SeekStart) fmt.Println("file1/2 光标已经移动到了目标位置") // 4、开始读写(复制、上传) bufData := make([]byte, 1024) // 5、需要记录读取了多少个字节 total := int(count) for { fmt.Println("传输了,", total) // 读取数据 readNum, err := file1.Read(bufData) if err == io.EOF || readNum == 0 { // file1 读取完毕了 fmt.Println("文件传输完毕了") //上传完文件再关闭临时文件file3 file3.Close() os.Remove(tempFile) break } // 向目标文件中写入数据,返回写的字节数和错误 writeNum, err := file2.Write(bufData[:readNum]) // 将写入数据放到 total中, 在这里total 就是传输的进度 total = total + writeNum // temp.txt 存放临时记录数据 file3.Seek(0, io.SeekStart) // 将光标重置到开头 //将数字转换成字符串写入,这里total逐渐变大不存在覆盖不完的问题。如果存在覆盖不完问题,使用os.Truncate(fileName, 0)来清空文件内容 // os.Truncate(fileName, 0) 截取指定长度字节的内容,其余内容会被删除 file3.WriteString(strconv.Itoa(total)) //模拟断电 //if total > 10000 { // panic("断电了") //} } }
模拟传输过程中出现问题,比如断电
恢复电后继续上传
以上就是Go语言中Seeker接口的用法详解的详细内容,更多关于Go Seeker接口用法的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论