3 回答

TA貢獻(xiàn)1798條經(jīng)驗 獲得超7個贊
最后編輯
這是對花費微不足道的時間的問題的“逐行”解決方案,它會打印整個匹配行。
package main
import (
"bytes"
"fmt"
"io/ioutil"
)
func main() {
dat, _ := ioutil.ReadFile("./jumble.txt")
i := bytes.Index(dat, []byte("Iforgotmypassword"))
if i != -1 {
var x int
var y int
for x = i; x > 0; x-- {
if dat[x] == byte('\n') {
break
}
}
for y = i; y < len(dat); y++ {
if dat[y] == byte('\n') {
break
}
}
fmt.Println(string(dat[x : y+1]))
}
}
real 0m0.421s
user 0m0.068s
sys 0m0.352s
原始答案
如果您只需要查看字符串是否在文件中,為什么不使用正則表達(dá)式呢?
注意:我將數(shù)據(jù)保存為字節(jié)數(shù)組而不是轉(zhuǎn)換為字符串。
package main
import (
"fmt"
"io/ioutil"
"regexp"
)
var regex = regexp.MustCompile(`Ilostmypassword`)
func main() {
dat, _ := ioutil.ReadFile("./jumble.txt")
if regex.Match(dat) {
fmt.Println("Yes")
}
}
jumble.txt是一個 859 MB 的包含換行符的混亂文本。
運行time ./code我得到:
real 0m0.405s
user 0m0.064s
sys 0m0.340s
為了嘗試回答您的評論,我不認(rèn)為瓶頸本質(zhì)上來自于逐行搜索,Golang 使用一種有效的算法來搜索字符串/符文。
我認(rèn)為瓶頸來自IO讀取,當(dāng)程序從文件讀取時,它通常不會在讀取隊列中排在第一位,因此,程序必須等到可以讀取才能開始實際比較。因此,當(dāng)您一遍又一遍地閱讀時,您將被迫等待輪到您的 IO。
給你一些數(shù)學(xué),如果你的緩沖區(qū)大小是 64 * 1024(或 65535 字節(jié)),你的文件是 1 GB。將 1 GB / 65535 字節(jié)除以檢查整個文件所需的 15249 次讀取。在我的方法中,我“一次”讀取整個文件并檢查構(gòu)造的數(shù)組。
我能想到的另一件事就是遍歷文件所需的循環(huán)總數(shù)以及每個循環(huán)所需的時間:
給定以下代碼:
dat, _ := ioutil.ReadFile("./jumble.txt")
sdat := bytes.Split(dat, []byte{'\n'})
for _, l := range sdat {
if bytes.Equal([]byte("Iforgotmypassword"), l) {
fmt.Println("Yes")
}
}
我計算出每個循環(huán)平均需要 32 納秒,字符串 Iforgotmypassword 在我的文件中的第 100000000 行,因此這個循環(huán)的執(zhí)行時間大約是 32 納秒 * 100000000 ~= 3.2 秒。

TA貢獻(xiàn)1853條經(jīng)驗 獲得超9個贊
H. Ross's answer is awesome,但它會將整個文件讀入內(nèi)存,如果你的文件太大,這可能不可行。如果您仍然想逐行掃描,也許如果您正在搜索多個項目,我發(fā)現(xiàn)使用 scanner.Bytes() 而不是 scanner.Text() 可以稍微提高我機器上的速度,從 2.244s 到原題,1.608s。bufio 的 scanner.Bytes() 方法不分配任何額外的內(nèi)存,而 Text() 從其緩沖區(qū)創(chuàng)建一個字符串。
package main
import (
"bufio"
"fmt"
"os"
"bytes"
)
// uses scanner.Bytes to avoid allocation.
func main() {
f, err := os.Open("./crackstation-human-only.txt")
scanner := bufio.NewScanner(f)
if err != nil {
panic(err)
}
defer f.Close()
toFind := []byte("Iforgotmypassword")
for scanner.Scan() {
if bytes.Contains(scanner.Bytes(), toFind) {
fmt.Println(scanner.Text())
}
}
}

TA貢獻(xiàn)1719條經(jīng)驗 獲得超6個贊
使用我自己的 700MB 測試文件和你的原始文件,時間剛剛超過 7 秒
使用 grep 是 0.49 秒
使用這個程序(不打印出行,它只是說是)0.082 秒
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
find := []byte(os.Args[1])
dat, err := ioutil.ReadFile("crackstation-human-only.txt")
check(err)
if bytes.Contains(dat, find) {
fmt.Print("yes")
}
}
- 3 回答
- 0 關(guān)注
- 277 瀏覽
添加回答
舉報