文件断点续传的基本实现

断点续传原理

每次拷贝时,使用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()即可

评论 抢沙发

表情
  1. #1

    来自北京朝阳的用户 9天前
    贼详细,收藏了