阅读 714

文件断点续传的基本实现

断点续传原理

每次拷贝时,使用seek记录偏移量,并将其记录在本地文件中,下次拷贝时读取时从记录的偏移量的位置继续进行

上次上传代码有错误,已修复

代码实现

  • 核心方法
func ContinueCopy(srcFile, destDir string) (int, error) {
	// 1. 定义源文件
	fileSrc, err := os.Open(srcFile)
	if err != nil {
		return 0, err
	}
	log.Printf("源文件名称:%s\n", fileSrc.Name())

	// 2. 定义目标文件位置,不存在时自动创建
	destFile := destDir + srcFile[strings.LastIndex(srcFile, "/")+1:]
	fileDest, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm)
	if err != nil {
		return 0, err
	}
	log.Printf("目标文件名称:%s\n", fileDest.Name())

	// 3. 定义零时文件位置,不存在时自动创建(不建议使用ioutil.TempFile(),不便下次找到)
	tempFile := destFile + "_temp"
	fileTemp, err := os.OpenFile(tempFile, os.O_WRONLY|os.O_CREATE, os.ModePerm)
	if err != nil {
		return 0, err
	}
	log.Printf("临时文件名称:%s\n", fileTemp.Name())

	// 4. 关闭文件
	defer fileSrc.Close()
	defer fileDest.Close()
	defer fileTemp.Close()

	// 6. 读取临时文件中的偏移量的值
	tempOffsetStr, err := ioutil.ReadFile(tempFile)
	tempOffSet, err := strconv.ParseInt(string(tempOffsetStr), 10, 64)

	// 7. 本次拷贝的初始位置
	fileSrc.Seek(tempOffSet, io.SeekStart)
	fileDest.Seek(tempOffSet, io.SeekStart)
	data := make([]byte, 1024, 1024)
	countOut := -1           //	读出的总量
	countIn := -1            // 写入的总量
	total := int(tempOffSet) // 总量

	srcRead := bufio.NewReader(fileSrc)
	destWrite := bufio.NewWriter(fileDest)

	// 8. 拷贝文件
	for {
		countOut, err = srcRead.Read(data)
		if err == io.EOF || countOut == 0 {
			log.Printf("文件拷贝完成,总共: %d字节\n", total)
			fileTemp.Close()
			os.Remove(tempFile)
			return 1, nil
		}
		//destFile := bufio.NewWriter(fileDest)
		countIn, err = destWrite.Write(data[:countOut])
		destWrite.Flush()
		total += countIn

		// 9. 将当前复制的偏移量,存储到临时文件
		fileTemp.Seek(0, io.SeekStart)
		fileTemp.WriteString(strconv.Itoa(total))

		// 10. 建设异常情况,突然终止拷贝
		UnknownErr(total)
	}
}
复制代码
  • 自定义终端程序运行的方法
// 2M时中断程序
func UnknownErr(n int) {
	if n == 1024*2 {
		panic("something has coursed error...")
	}
}
复制代码
  • 测试运行
func main() {
	srcFile := "e:/temp/img02.jpg"
	destDir := "d:/pic/"

	_, err := ContinueCopy(srcFile, destDir)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("拷贝完成")
}
复制代码

运行效果

  • 第一次运行,遭遇中断

  • 第二次继续运行

第二次拷贝文件,自动从2048的位置开始拷贝,完成后自动删除

注:如果文件内容很小,如小于缓冲区,可以直接使用io.Copy()即可

关注下面的标签,发现更多相似文章
评论