Go語言Seeker接口與文件斷點(diǎn)續(xù)傳實(shí)戰(zhàn)教程
Seeker接口
在現(xiàn)代軟件開發(fā)中,高效的輸入輸出(I/O)操作是提高程序性能的關(guān)鍵之一。特別是在處理大量數(shù)據(jù)時(shí),I/O操作的效率直接影響到應(yīng)用程序的響應(yīng)速度和用戶體驗(yàn)。Go語言標(biāo)準(zhǔn)庫(kù)中的io包提供了一系列接口,用于處理各種I/O操作,其中Seeker接口在處理大文件或需要隨機(jī)訪問的場(chǎng)景中非常有用。本文將結(jié)合具體案例,詳細(xì)介紹Go語言中io包的Seeker接口的用法。
一、Seeker接口簡(jiǎn)介
設(shè)置光標(biāo)的位置,通過設(shè)置的光標(biāo)位置來讀寫文件
用于在數(shù)據(jù)流中將光標(biāo)跳轉(zhuǎn)到指定的位置
Seeker接口表示一個(gè)定位器,可以用來定位文件或流的位置。其定義如下:
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}Seek方法接受兩個(gè)參數(shù):
offset:相對(duì)位移量,表示從起始位置移動(dòng)的字節(jié)數(shù)。
whence:起始位置,可以是以下三個(gè)常量之一:
- io.SeekStart:從文件開頭開始計(jì)算偏移量。
- io.SeekCurrent:從當(dāng)前文件指針位置開始計(jì)算偏移量。
- io.SeekEnd:從文件末尾開始計(jì)算偏移量(此時(shí)offset通常為負(fù)數(shù),表示向前移動(dòng))。

Seek方法返回兩個(gè)值:
- position:移動(dòng)后的文件指針位置(相對(duì)于文件開頭的字節(jié)數(shù))。
- err:可能發(fā)生的錯(cuò)誤。
二、Seeker接口的應(yīng)用場(chǎng)景
隨機(jī)訪問大文件:對(duì)于非常大的文件,通過Seek方法可以直接定位到文件的任意位置進(jìn)行讀寫操作,而不需要從頭開始遍歷文件。
斷點(diǎn)續(xù)傳:在網(wǎng)絡(luò)傳輸或文件復(fù)制等場(chǎng)景中,如果傳輸過程中斷,可以通過Seek方法定位到上次傳輸?shù)臄帱c(diǎn),繼續(xù)傳輸剩余的數(shù)據(jù)。
日志文件分析:對(duì)于包含多條記錄的日志文件,可以通過Seek方法快速定位到特定記錄的位置,進(jìn)行日志分析或錯(cuò)誤排查。
三、Seeker接口的使用示例
以下是一個(gè)結(jié)合具體案例的示例代碼,展示了如何使用Seeker接口來定位文件位置并進(jìn)行讀寫操作。
File對(duì)象實(shí)現(xiàn)了Seeker接口

file對(duì)象可以直接調(diào)用Seek方法
我們先看下a.txt文件

代碼示例:
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 讀取文件
file, _ := os.OpenFile("F:\\goworks\\src\\jingtian\\yufa\\io操作\\a.txt", os.O_RDWR, os.ModePerm)
// defer close
defer file.Close()
// 測(cè)試seek
// 相對(duì)開始位置。io.SeekStart
// 相對(duì)于文件末尾, io.SeekEnd
// func (f *File) Seek(offset int64, whence int) (ret int64, err error)
//相對(duì)于開始位置,光標(biāo)偏移兩個(gè)字節(jié)
file.Seek(2, io.SeekStart)
//創(chuàng)建一個(gè)字節(jié)的buffer
buf := []byte{0}
file.Read(buf)
fmt.Println(string(buf)) // n
//Read讀了一個(gè)字節(jié), 光標(biāo)現(xiàn)在在3這個(gè)位置
// 相對(duì)于當(dāng)前位置
file.Seek(3, io.SeekCurrent)
file.Read(buf)
fmt.Println(string(buf)) // a
// 在結(jié)尾追加內(nèi)容
//相對(duì)于結(jié)束位置偏移0,光標(biāo)就設(shè)在了結(jié)束位置
file.Seek(0, io.SeekEnd)
//寫入內(nèi)容
file.WriteString("hahahaha")
}運(yùn)行

再看下a.txt,可見在末尾寫入了我們指定的內(nèi)容

四、斷點(diǎn)續(xù)傳
斷點(diǎn)續(xù)傳是在下載或上傳時(shí),將下載或上傳任務(wù)(一個(gè)文件或一個(gè)壓縮包)人為的劃分為幾個(gè)部分,每一個(gè)部分采用一個(gè)線程進(jìn)行上傳或下載,如果碰到網(wǎng)絡(luò)故障,可以從已經(jīng)上傳或下載的部分開始繼續(xù)上傳或者下載未完成的部分,而沒有必要從頭開始上傳或者下載。
go語言實(shí)現(xiàn)斷點(diǎn)續(xù)傳的思路:
使用臨時(shí)文件記錄中斷位置.
1.文件上傳時(shí),先創(chuàng)建上傳一個(gè)新的文件
2.創(chuàng)建記錄中斷位置的臨時(shí)文件,需要記住上一次傳遞了多少數(shù)據(jù)、temp.txt
3.設(shè)置文件讀寫偏移量,如果被暫?;蛘咧袛嗔?,我們就可以讀取這個(gè)temp.txt的記錄,恢復(fù)上傳
4.上傳完成后,刪除臨時(shí)文件

package main
import (
"fmt"
"io"
"os"
"strconv"
)
// 斷點(diǎn)續(xù)傳
func main() {
// 傳輸源文件地址
srcFile := "D:\\downloads\\mingw.7z"
// 傳輸?shù)哪繕?biāo)位置
destFile := "F:\\goworks\\src\\jingtian\\yufa\\io操作\\server\\mingw.7z"
// 臨時(shí)記錄文件
tempFile := "F:\\goworks\\src\\jingtian\\yufa\\io操作\\temp.txt"
// 創(chuàng)建對(duì)應(yīng)的file對(duì)象,連接起來
file1, _ := os.Open(srcFile)
file2, _ := os.OpenFile(destFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
file3, _ := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
defer file1.Close()
defer file2.Close()
fmt.Println("file1/2/3 文件連接建立完畢")
// 1、讀取temp.txt
file3.Seek(0, io.SeekStart)
buf := make([]byte, 1024)
n, _ := file3.Read(buf) //這里的n是讀取file3中的字符的個(gè)數(shù),比如1024,得到的n是4.所以要借助string轉(zhuǎn)
//查看返回的n的數(shù)據(jù)類型
fmt.Printf("查看n的數(shù)據(jù)類型%T\n", n)
fmt.Println("n的值為", n)
// 2、先轉(zhuǎn)換成string,然后再轉(zhuǎn)換成數(shù)字。
countStr := string(buf[:n])
count, _ := strconv.ParseInt(countStr, 10, 64)
fmt.Println("temp.txt中記錄的值為:", count) // 5120
// 3、設(shè)置讀寫的偏移量,offset是int64數(shù)據(jù)類型
file1.Seek(count, io.SeekStart)
file2.Seek(count, io.SeekStart)
fmt.Println("file1/2 光標(biāo)已經(jīng)移動(dòng)到了目標(biāo)位置")
// 4、開始讀寫(復(fù)制、上傳)
bufData := make([]byte, 1024)
// 5、需要記錄讀取了多少個(gè)字節(jié)
total := int(count)
for {
fmt.Println("傳輸了,", total)
// 讀取數(shù)據(jù)
readNum, err := file1.Read(bufData)
if err == io.EOF || readNum == 0 { // file1 讀取完畢了
fmt.Println("文件傳輸完畢了")
//上傳完文件再關(guān)閉臨時(shí)文件file3
file3.Close()
os.Remove(tempFile)
break
}
// 向目標(biāo)文件中寫入數(shù)據(jù),返回寫的字節(jié)數(shù)和錯(cuò)誤
writeNum, err := file2.Write(bufData[:readNum])
// 將寫入數(shù)據(jù)放到 total中, 在這里total 就是傳輸?shù)倪M(jìn)度
total = total + writeNum
// temp.txt 存放臨時(shí)記錄數(shù)據(jù)
file3.Seek(0, io.SeekStart) // 將光標(biāo)重置到開頭
//將數(shù)字轉(zhuǎn)換成字符串寫入,這里total逐漸變大不存在覆蓋不完的問題。如果存在覆蓋不完問題,使用os.Truncate(fileName, 0)來清空文件內(nèi)容
// os.Truncate(fileName, 0) 截取指定長(zhǎng)度字節(jié)的內(nèi)容,其余內(nèi)容會(huì)被刪除
file3.WriteString(strconv.Itoa(total))
//模擬斷電
//if total > 10000 {
// panic("斷電了")
//}
}
}
模擬傳輸過程中出現(xiàn)問題,比如斷電

恢復(fù)電后繼續(xù)上傳

到此這篇關(guān)于Go語言Seeker接口與文件斷點(diǎn)續(xù)傳實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Go斷點(diǎn)續(xù)傳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用GO實(shí)現(xiàn)IP門禁優(yōu)化網(wǎng)絡(luò)流量管理
這篇文章主要為大家介紹了用GO實(shí)現(xiàn)IP門禁優(yōu)化網(wǎng)絡(luò)流量管理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
使用Golang實(shí)現(xiàn)加權(quán)負(fù)載均衡算法的實(shí)現(xiàn)代碼
這篇文章主要介紹了使用Golang實(shí)現(xiàn)加權(quán)負(fù)載均衡算法的實(shí)現(xiàn)代碼,詳細(xì)說明權(quán)重轉(zhuǎn)發(fā)算法的實(shí)現(xiàn),通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
Go語言非main包編譯為靜態(tài)庫(kù)并使用的示例代碼
本文以Windows為例,介紹一下如何將Go的非main包編譯為靜態(tài)庫(kù),用戶又將如何使用。通過實(shí)際項(xiàng)目創(chuàng)建常規(guī)工程,通過示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-07-07
8種超簡(jiǎn)單的Golang生成隨機(jī)字符串方式分享
這篇文章主要為大家詳細(xì)介紹了8種超簡(jiǎn)單的Golang生成隨機(jī)字符串方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
Go語言函數(shù)的延遲調(diào)用(Deferred Code)詳解
本文將介紹Go語言函數(shù)和方法中的延遲調(diào)用,正如名稱一樣,這部分定義不會(huì)立即執(zhí)行,一般會(huì)在函數(shù)返回前再被調(diào)用,我們通過一些示例來了解一下延遲調(diào)用的使用場(chǎng)景2022-07-07

