断点续传原理
每次拷贝时,使用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()
即可
有疑问加站长微信联系(非本文作者)