断点续传原理
每次拷贝时,使用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()
即可
来自河南郑州的用户 9天前
很棒,很棒