断点续传
# 端点续传
Seek方法地址:
https://golang.google.cn/pkg/io/#Seeker
# 一、Seeker接口
Seeker
是包装基本Seek
方法的接口.
type Seeker interface {
Seek(offset int64,whence int)(int64,error)
}
1
2
3
2
3
seek(offset,whence)
,设置指针光标的位置,随机读写文件
第一个参数: 偏移量
第二参数: 如何设置
0:
SeekStart
表示相对于文件开始 1:
seekCurrent
表示相对于当前偏移量 2:
seek end
表示相对于结束
// Seek whence values.
const (
SeekStart = 0 // seek relative to the origin of the file
SeekCurrent = 1 // seek relative to the current offset
SeekEnd = 2 // seek relative to the end
)
1
2
3
4
5
6
2
3
4
5
6
示例代码:
package main
import (
"fmt"
"io"
"log"
"os"
)
func main() {
/*
Seek(offset int64, whence int) (int64, error), 设置指针光标的位置
第一个参数: 偏移量
第二个参数: 如何设置
0: seekstart,表示对于文件开始
1: seekcurrent,表示相对于当前位置的偏移量
2: seekend,表示相对于末尾
// Seek whence values.
const (
SeekStart = 0 // seek relative to the origin of the file
SeekCurrent = 1 // seek relative to the current offset
SeekEnd = 2 // seek relative to the end
)
*/
fileName := "E:\\Github-Project\\GO-Project\\src\\upgrade-qf\\03.file\\aa.txt"
file, err := os.OpenFile(fileName, os.O_RDWR, os.ModePerm)
if err != nil {
log.Fatal(err)
}
defer file.Close()
//读写
bs := []byte{0}
file.Read(bs)
fmt.Println(string(bs))
file.Seek(4, io.SeekStart)
file.Read(bs)
fmt.Println(string(bs))
file.Seek(2, 0) //SeekStart
file.Read(bs)
fmt.Println(string(bs))
file.Seek(3, io.SeekCurrent)
file.Read(bs)
fmt.Println(string(bs))
file.Seek(0, io.SeekEnd)
file.WriteString("ABC")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
运行结果
$ go run 03.file/seeker.go
a
e
c
g
1
2
3
4
5
6
2
3
4
5
6
# 二、断点续传
思考几个问题
- 如果要传的问家庭,比较大,那么是否有方法可以缩短耗时?
- 如果在文件传递过程中,程序因各种原因被迫中断了,那么下次再重启时,文件是否需要重头开始?
- 传递文件的时候,支持暂停和恢复么? 及时这两个操作分布在程序进程被杀前后.
通过端点续传可以实现,不同的语言有不同的实现方式.在Go
语言中,通过Seek()
方法如何实现:
思路: 想实现端点续传,主要就是记住上一次已经传递了多少数据,那么可以创建一个临时文件,记录已经传递的数据量,当恢复传递的时候,先从临时文件中读取上次已经传递的数据量,然后通过Seek()
方法,设置到该读和该写的位置,再继续传递数据.
package main
import (
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
)
func main() {
/*
端点续传:
文件传递: 文件复制
"E:\\Github-Project\\GO-Project\\src\\upgrade-qf\\03.file\\go.jpg"
复制到当前工程下:
思路: 边复制,边记录复制的总量
*/
srcFile := "E:\\Github-Project\\GO-Project\\src\\upgrade-qf\\03.file\\shaonv.jpg"
destFile := "new" + srcFile[strings.LastIndex(srcFile, "\\")+1:] // 这里需要注意的是`Linux`系统下的分隔符"\";`Windows`系统下的分隔符“\\”
tempFile := destFile + "temp.txt"
//fmt.Println(tempFile)
file1, _ := os.Open(srcFile)
file2, _ := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, os.ModePerm)
file3, _ := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
defer file1.Close()
defer file2.Close()
//1.读取临时文件中的数据,根据seek
file3.Seek(0, io.SeekStart)
bs := make([]byte, 100, 100)
n1, err := file3.Read(bs)
fmt.Println(n1)
countStr := string(bs[:n1])
fmt.Println(countStr)
//count,_:=strconv.Atoi(countStr)
count, _ := strconv.ParseInt(countStr, 10, 64)
fmt.Println(count)
//2. 设置读,写的偏移量
file1.Seek(count, 0)
file2.Seek(count, 0)
data := make([]byte, 1024, 1024)
n2 := -1 // 读取的数据量
n3 := -1 //写出的数据量
total := int(count) //读取的总量
for {
//3.读取数据
n2, err = file1.Read(data)
if err == io.EOF || n2 == 0 {
fmt.Println("文件复制完毕...", total)
file3.Close()
os.Remove(tempFile)
break
}
//将数据写入到目标文件
n3, _ = file2.Write(data[:n2])
total += n3
//将复制总量,存储到临时文件中
file3.Seek(0, io.SeekStart)
file3.WriteString(strconv.Itoa(total))
fmt.Printf("当前复制的数据总量: %d\n", total)
//假装断电
//if total > 8000 {
// panic("假装断电了。。。,假装的。。。")
//}
}
}
func HandlerErr(err error) {
if err != nil {
log.Fatal(err)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
上次更新: 2024/04/09, 16:48:42
- 01
- AWS NAT-NetWork-Firwalld配置(一)04-09
- 02
- AWS NAT-NetWork-Firwalld配置(二)04-09
- 03
- kubernetes部署minio对象存储01-18