golang断点续传

场景

当我们用百度网盘下载或者迅雷下载时,某一时刻下到一半不想下了,按了暂停,关了程序,关了机,第二天打开百度网盘,继续下昨天的东西,发现,是从昨天暂停的地方开始继续下载的,这种体验就很棒。不然,像百度云盘不充会员只有100k左右的下载速度,一下午加一晚上好不容易下了一半,睡觉去了,第二天打开电脑接着下,发现还要重新开始,看着这老牛的速度,崩溃了。这就体现了断点续传的妙用了。
我们用client模拟百度云盘,迅雷等app,用server模拟申请下载方。

文件上传一方

1、整体思路
对于client端上传文件,需要先知道断点在哪里,也就是说需要从服务器读一个整型,这个数代表下载一方上次读到哪了,然后文件光标偏移到这个地方,读文件,写入连接,完成上传文件。
2、代码实现
⚪获取连接

conn, err := net.Dial("tcp","localhost:8080")
	if err != nil{
		fmt.Println("net.Dial err", err)
		return
	}
defer conn.Close()

⚪告诉下载方开始上传

defer conn.Close()

⚪读取下载方传来的上次下载的位置

buf := make([]byte, 10,10)
n,err:=conn.Read(buf)
if err !=nil{
	fmt.Println("conn.Read err", err)
	return
}

⚪光标偏移到上次下载的位置

pos,_ := strconv.Atoi(string(buf[:n]))
file.Seek(int64(pos),0)

⚪循环读取读取文件直到结束

for{
	buf:=make([]byte,10,10)
	n,err:=file.Read(buf)
	if err==io.EOF{
		conn.Write([]byte("<--end"))
		fmt.Println("传输完成")
		return
	}else{
		conn.Write(buf[:n])
	}
}

这里模拟的再真实一点,在file.read之前可以conn.Read一下,如果下载方传了一个”暂停“,上传一方直接break,这也防止了异常退出带来的不可预料的错误

文件下载一方

1、对于server端下载文件,在建立连接之后,需要先发送文件的字节长度,代表上次读到哪了,然后读连接,写入文件,完成下载文件

2.代码实现
⚪首先解释一下如何获得上次下载的位置
就是看看本地文件有多少个字节。用到os.Stat函数,返回一个文件信息,文件信息里有文件的大小,如果没有该文件返回一个os.IsNotExist,文件不存在大小肯定是0,

func Stat(name string) (fi FileInfo, err error)

下面编程

func GetPos(filepath string)int64{
	file, err := os.Stat(filepath)
	if err != nil{
		if os.IsNotExist(err){
			return 0
		}
	}
	return file.Size()
}

⚪监听端口,得到连接

listener,err := net.Listen("tcp", "localhost:8080")
	if err != nil{
		fmt.Println("net.Listen err", err)
		return
	}
	conn,err := listener.Accept()
	if err != nil{
		fmt.Println("listener.Accept err", err)
		return
	}

⚪得到pos,如果大小为零,就创建一个文件,否则就以追加写的方式打开,得到可用于i/o的文件句柄。

filepath := "G:\\BaiduNetdiskDownload\\CSDN算法\\小课资料\\day10\\Get作业.txt"
	pos := int(GetPos(filepath))
	intstr:= strconv.Itoa(pos)
	var file *os.File
	if pos==0{
		file,_ = os.Create(filepath)
	}else{
		file,_ = os.OpenFile(filepath,os.O_APPEND,0777)
	}

⚪循环读连接,如果读到“start–>”,表示上传方做好了准备,这时要先发一个pos,告诉上传方上次读到哪了了,然后从链接继续读,写入本地文件,知道读到“end"关闭连接,关闭文件句柄

for{
		buf := make([]byte,10,10)
		n,err := conn.Read(buf)
		if err != nil{
			if err == io.EOF{
				fmt.Println("连接断开了")
				return
			}
			fmt.Println("read err", err)
			return
		}
		if  n != 0{
			if string(buf[:n])=="start-->"{
				conn.Write([]byte(intstr))
			}else if string(buf[:n])=="<--end"{
				fmt.Println("客户端传输完成")
				file.Close()
			}else{
				fmt.Println("正在写入文件:", string(buf[:n]))
				_,err:=file.Write(buf[:n])
				if err != nil{
					fmt.Println("写入",err)
				}
			}
		}
	}

你可能感兴趣的:(go,os)