91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang怎么讀取單行超長的文本

發布時間:2021-12-22 10:22:35 來源:億速云 閱讀:177 作者:iii 欄目:開發技術

這篇文章主要介紹“Golang怎么讀取單行超長的文本”,在日常操作中,相信很多人在Golang怎么讀取單行超長的文本問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Golang怎么讀取單行超長的文本”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

1.問題復現

首先注釋main函數里面的內容,執行 CreateBigText 函數,它會創建一個含有3行內容的文件,第一行是一個長度超過100KB的行。然后解決main函數的注釋,嘗試執行代碼,會發現只有一行錯誤信息:

Golang怎么讀取單行超長的文本

package main

import (
	"bufio"
	"bytes"
	"log"
	"os"
	"strconv"
)

func main() {
	file, err := os.Open("./read/test.txt")
	if err != nil {
		log.Fatal(err)
	}
	ReadBigText(file)
}

func ReadBigText(file *os.File) {
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		println(scanner.Text())
	}
	// 輸出錯誤
	println(scanner.Err().Error())
}

func CreateBigText() {
	file, err := os.Create("./read/test.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	data := make([]byte, 0, 32*1024)
	buffer := bytes.NewBuffer(data)
	// 構造一個大的單行數據
	for i := 0; i < 50000; i++ {
		buffer.WriteString(strconv.Itoa(i))
	}
	// 寫入一個換行符
	buffer.WriteByte('\n')
	buffer.WriteString("I love you yesterday and today!\n")
	buffer.WriteString("有一美人兮,見之不忘。\n")
	// 將3行寫入文件
	file.Write(buffer.Bytes())
	log.Println("創建文件成功")
}

2.問題探究

讓我們來探究一下這個問題的原因,首先看一下Scan()方法的注釋,這個方法就是每次掃描到下一個token,然后就可以通過獲取字節或者文本的方法來獲取掃描過的token。如果它返回值是false,就會返回掃描期間遇到的錯誤,除了io.EOF.

Scan advances the Scanner to the next token, which will then be available through the Bytes or Text method. It returns false when the scan stops, either by reaching the end of the input or an error. After Scan returns false, the Err method will return any error that occurred during scanning, except that if it was io.EOF, Err will return nil. Scan panics if the split function returns too many empty tokens without advancing the input. This is a common error mode for scanners.

所以Scan()和Text()函數是這樣結合起來使用的,首先Scan()會掃描出一個token,然后Text()將其轉成文本(或者其它方法轉成字節),循環執行這種操作就可以按行讀取一個文件。

通過閱讀Scan()函數的源碼,我們可以發現這樣一個判斷,如果buf的長度大于了最大token長度,那就會報錯,見下圖。

Golang怎么讀取單行超長的文本

繼續查找,可以看到最大長度已經定義好了,它的長度是 64*1024 byte,即64KB,所以一行文本超過了這個最大長度,那么就會報錯!

Golang怎么讀取單行超長的文本

3.問題解決

其實大部分情況下我們都應該使用Scan()函數結合Text()或者Bytes()函數來讀取文件的,這個也是官方推薦的,因為它們是 high-level 方法,用起來很方便。但是如果我們有一些極端的情況,例如單行超過64KB,那么怎么辦呢?(這種情況是很少的,但是又有可能會遇到這種需求的,例如文件里面存儲了一串Base64編碼)

這里可以這樣來使用,這個方法不會受到64KB的限制,ReaderString方法會按照指定的定界符來讀取一個完整的行,返回值是字符串和讀取遇到的錯誤。如果想要讀取返回值為字節的話,可以使用 ReadBytes 方法。

func ReadBigText(file *os.File) {
	defer file.Close()
	reader := bufio.NewReader(file)
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%d %s", len(line), line)
	}
}

Golang怎么讀取單行超長的文本

通過閱讀源碼可知,其實這個方法也是會遇到行太長的問題,只不過它忽略了這種情況。

ErrBufferFull就是這個緩沖區溢出錯誤。

Golang怎么讀取單行超長的文本

我們繼續進入內容其實也可以知道,它默認的緩沖區大小是4KB。

Golang怎么讀取單行超長的文本

4.擴展

上面都說相對高層的方法,我們來看一下相對底層的方法。

ReadLine is a low-level line-reading primitive. Most callers should use ReadBytes('\n') or ReadString('\n') instead or use a Scanner.

ReadLine是讀取一行,但是它是一個 low-level 方法,它會返回三個值:[]byte、isPrefix bool和err error。
其中最令人好奇的是第二個參數,它如果是true,則表示當前行沒有讀取完畢,但是緩沖區滿了,可以看下面這段注釋。

If the line was too long for the buffer then isPrefix is set and the beginning of the line is returned. The rest of the line will be returned from future calls.

func ReadBigText(file *os.File) {
	defer file.Close()
	reader := bufio.NewReader(file)

	for {
		bline, isPrefix, err := reader.ReadLine()
		if err == io.EOF {
			break // 讀取到文件結束才退出
		}
		// 讀取到超長行,即單行超過4k字節,直接寫入文件,不對此行做處理
		if isPrefix {
			fmt.Print(string(bline))
			continue
		}

		fmt.Println(string(bline))
	}
}

Golang怎么讀取單行超長的文本

不過需要注意這個方法讀取出來的數據是不包括換行符的,所以我是用的println打印輸出的。

如果你也去看了 ReadStringReadBytesReadLine 方法,會發現兩種都依賴于一個底層的方法——ReadSlice方法。這個方法很原始,一般不會直接使用它。如果它遇到了超長行,它就會直接返回讀取到的字節和一個ErrBufferFull,那這樣我們就可以根據這個錯誤來繼續讀取數據了。這種方式還是相對麻煩了一些,不過如果你可以理解的話,對于上面的方法也就不是問題了。學習嘛,還是有必要一探究竟的。不過閱讀源碼感覺有些還是理解起來很困難,特別是這些英語注釋,不過也能看一個七七八八了。還不行的話,那就再借助一些翻譯軟件,不過我個人覺得提高自己的英語能力還是非常必要的。

func ReadBigText(file *os.File) {
	defer file.Close()
	reader := bufio.NewReader(file)
	for {
		byt, err := reader.ReadSlice('\n')
		if err != nil {
			if err == bufio.ErrBufferFull {
				fmt.Print(string(byt))
				continue
			}
			log.Fatal(err)
		}
		fmt.Print(string(byt))
	}
}

Golang怎么讀取單行超長的文本

到此,關于“Golang怎么讀取單行超長的文本”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

贺州市| 木里| 鹤山市| 广平县| 湖口县| 乐昌市| 班戈县| 武鸣县| 三门峡市| 长沙市| 鄂托克前旗| 贡觉县| 阳信县| 泗水县| 繁峙县| 古浪县| 阿拉善右旗| 南和县| 新乡县| 金昌市| 虹口区| 三亚市| 江华| 双江| 绍兴县| 行唐县| 北票市| 金乡县| 鹤山市| 松滋市| 葫芦岛市| 乐清市| 密山市| 泰州市| 邳州市| 遂昌县| 马龙县| 攀枝花市| 普安县| 兴城市| 临洮县|