Seeker 接口
Seeker 是包裝基本 Seek 方法的接口。
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}
seek(offset,whence)经备,設(shè)置指針光標的位置捻爷,隨機讀寫文件:
第一個參數(shù):偏移量
?第二個參數(shù):如何設(shè)置
0:seekStart表示相對于文件開始疑苔,
?1:seekCurrent表示相對于當前偏移量镜豹,
?2:seek end表示相對于結(jié)束傲须。
const (
SeekStart = 0 // seek relative to the origin of the file
SeekCurrent = 1 // seek relative to the current offset
SeekEnd = 2 // seek relative to the end
)
我們要讀取本地 /Users/ruby/Documents/pro/a 目錄下的 aa.txt 文件,文件中的內(nèi)容是:abcdefghij 這幾個字符趟脂。
示例代碼:
package main
import (
"os"
"fmt"
"io"
)
func main() {
/*
seek(offset,whence),設(shè)置指針光標的位置
第一個參數(shù):偏移量
第二個參數(shù):如何設(shè)置
0:seekStart表示相對于文件開始泰讽,
1:seekCurrent表示相對于當前偏移量,
2:seek end表示相對于結(jié)束昔期。
const (
SeekStart = 0 // seek relative to the origin of the file
SeekCurrent = 1 // seek relative to the current offset
SeekEnd = 2 // seek relative to the end
)
隨機讀取文件:
可以設(shè)置指針光標的位置
*/
file,_:=os.OpenFile("/Users/ruby/Documents/pro/a/aa.txt",os.O_RDWR,0)
defer file.Close()
bs :=[]byte{0}
file.Read(bs)
fmt.Println(string(bs))
file.Seek(4,io.SeekStart)
file.Read(bs)
fmt.Println(string(bs))
file.Seek(2,0) //也是SeekStart
file.Read(bs)
fmt.Println(string(bs))
file.Seek(3,io.SeekCurrent)
file.Read(bs)
fmt.Println(string(bs))
file.Seek(0,io.SeekEnd)
file.WriteString("ABC")
}
運行結(jié)果:
本地文件:
斷點續(xù)傳
首先思考幾個問題
Q1:如果你要傳的文件已卸,比較大,那么是否有方法可以縮短耗時硼一?
Q2:如果在文件傳遞過程中累澡,程序因各種原因被迫中斷了般贼,那么下次再重啟時愧哟,文件是否還需要重頭開始?
Q3:傳遞文件的時候哼蛆,支持暫停和恢復(fù)么蕊梧?即使這兩個操作分布在程序進程被殺前后。
通過斷點續(xù)傳可以實現(xiàn)腮介,不同的語言有不同的實現(xiàn)方式肥矢。我們看看 Go 語言中,通過 Seek() 方法如何實現(xiàn):
先說一下思路:想實現(xiàn)斷點續(xù)傳叠洗,主要就是記住上一次已經(jīng)傳遞了多少數(shù)據(jù)甘改,那我們可以創(chuàng)建一個臨時文件,記錄已經(jīng)傳遞的數(shù)據(jù)量灭抑,當恢復(fù)傳遞的時候楼誓,先從臨時文件中讀取上次已經(jīng)傳遞的數(shù)據(jù)量,然后通過Seek()方法名挥,設(shè)置到該讀和該寫的位置疟羹,再繼續(xù)傳遞數(shù)據(jù)。
示例代碼:
package main
import (
"fmt"
"os"
"strconv"
"io"
)
func main() {
/*
斷點續(xù)傳:
文件傳遞:文件復(fù)制
/Users/ruby/Documents/pro/a/guliang.jpeg
復(fù)制到
guliang4.jpeg
思路:
邊復(fù)制禀倔,邊記錄復(fù)制的總量
*/
srcFile:="/Users/ruby/Documents/pro/a/guliang.jpeg"
destFile:="guliang4.jpeg"
tempFile:=destFile+"temp.txt"
//fmt.Println(tempFile)
file1,_:=os.Open(srcFile)
file2,_:=os.OpenFile(destFile,os.O_CREATE|os.O_WRONLY,os.ModePerm)
file3,_:=os.OpenFile(tempFile,os.O_CREATE|os.O_RDWR,os.ModePerm)
defer file1.Close()
defer file2.Close()
//1.讀取臨時文件中的數(shù)據(jù)榄融,根據(jù)seek
file3.Seek(0,io.SeekStart)
bs:=make([]byte,100,100)
n1,err:=file3.Read(bs)
fmt.Println(n1)
countStr:=string(bs[:n1])
fmt.Println(countStr)
//count,_:=strconv.Atoi(countStr)
count,_:=strconv.ParseInt(countStr,10,64)
fmt.Println(count)
//2. 設(shè)置讀,寫的偏移量
file1.Seek(count,0)
file2.Seek(count,0)
data:=make([]byte,1024,1024)
n2:=-1// 讀取的數(shù)據(jù)量
n3:=-1//寫出的數(shù)據(jù)量
total :=int(count)//讀取的總量
for{
//3.讀取數(shù)據(jù)
n2,err=file1.Read(data)
if err ==io.EOF{
fmt.Println("文件復(fù)制完畢救湖。愧杯。")
file3.Close()
os.Remove(tempFile)
break
}
//將數(shù)據(jù)寫入到目標文件
n3,_=file2.Write(data[:n2])
total += n3
//將復(fù)制總量,存儲到臨時文件中
file3.Seek(0,io.SeekStart)
file3.WriteString(strconv.Itoa(total))
//假裝斷電
//if total>8000{
// panic("假裝斷電了鞋既。力九。耍铜。,假裝的跌前。棕兼。。")
//}
}
}
加入這里(https://t.zsxq.com/zBAQNbu)抵乓,每天都有 Golang 初級到高級進階視頻更新