我需要在 Go 中處理一個大檔案,所以我不想一次性加載 csv 檔案中的所有行,而是按組處理它們。
為了從我離開的地方重新開始計算這些行,我實際上使用了一個for回圈來跳過已經讀過的行:
for idx := 0; idx < startAt; idx {
/Read rows and do nothing with the return value[/span]。
if _, readErr := reader.Read(); readErr != nil {
if readErr == io.EOF {
/File end -> OK
isEOF = true
break。
} else {
//Read failed {
return nil, errors.New(DATA_READ_ERROR)
}
}
}
這是一個相當簡單的解決方案;但是,它顯然是低效的。在閱讀完第一行之后,閱讀以下內容的時間會呈指數級增長。
為了減少這個時間,我嘗試了不同的替代方案,但每一個方案都不能正常作業,并使讀取器失敗(沒有從正確的地址讀取行)。
例如,我嘗試回傳檔案指標的當前位置(使用file.Seek(0, io.SeekCurrent),然后,在新的迭代中,我嘗試使用file.Seek(oldPosition, io.SeekStart)移動指標,但它沒有像預期的那樣作業。
有什么方法可以避免上述回圈,并在從我離開的地方重新開始時改善閱讀時間?
Update
我使用檔案Seek的方式非常簡單。
//compute data。
func computeData(nrows int, startAt int64) {
//Open file
if csvFile, openErr := os.Open(config.DataSrcFile); openErr == nil {
//創建一個閱讀器。
reader := csv.NewReader(csvFile)
//Position the file pointer to the start point[/span].
file.Seek(startAt, io.SeekStart)
//Read n rows[/span]。
for idx := 0; idx < *nrows & & !isEOF; idx {
if csvLine, readErr := reader.Read(); readErr == nil {
//Do stuff...
} else {
//Error registered reading csv }
if readErr == io.EOF {
/File end -> OK
break。
} else {
//Return error {
}
}
}
//Return bytes read(實際上是簡化了,在實際情況下,錯誤不是)。
//忽略)。
bytesRead, _ := file.Seek(0, io.SeekCurrent)
return bytesRead
}
}
func main() {
var startAt int64 = 0
nrows :=1000
for !isMyConditionMatched {
bytesRead = computeData(nrows, startAt)
startAt = bytesRead
}
}
uj5u.com熱心網友回復:
這里的問題是,encoding/csv內部使用了一個緩沖的閱讀器,所以當你執行file.Seek(0, io.SeekCurrent)時,你得到了底層檔案上的位置,但是有些資料被讀取了,你沒有使用它。
有兩種可能的解決方案:
。- 一個是使用較低級別的實作,允許控制你的確切位置 。
- 另一個是找出有多少緩沖的資料。
我將向你展示第二個選項的實作(注意,這依賴于對encoding/csv包的內部作業的一些了解,如果它被改變,可能會停止作業)
首先,在創建csv之前,你要創建一個新的有緩沖的io閱讀器:
//Position the file pointer to the start point.
file.Seek(startAt, io.SeekStart)
bReader := bufio.NewReader(file)
//創建一個閱讀器
reader := csv.NewReader(bReader)
這將允許你訪問緩沖區。你可以像你已經做的那樣使用這個閱讀器,但最后你要通過以下操作來計算檔案上的最終位置:
bufSize := bReader.Buffered()
filePos, err := file.Seek(0, io.SeekCurrent)
return filePos - int64(bufSize)
這將獲取檔案中的當前位置并移除創建的緩沖區。
注意,回傳的值是檔案中的位置,而不是在這個函式呼叫中讀取的位元組數。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/310224.html
標籤:
