欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang如何讀取單行超長的文本詳解

 更新時間:2021年12月22日 09:13:39   作者:CrazyDragon_King  
這篇文章主要給大家介紹了關(guān)于Golang如何讀取單行超長文本的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

前言:

最近在探索用Go來讀取文件,讀取文本時發(fā)現(xiàn),對于單行超長的文本,我的Go代碼無法處理。經(jīng)過查閱才發(fā)現(xiàn),Go提供的Scanner無法讀取單行超長文本文件。我這里就來總結(jié)一下問題的發(fā)現(xiàn)和解決過程。

1.問題復(fù)現(xiàn)

首先注釋main函數(shù)里面的內(nèi)容,執(zhí)行 CreateBigText 函數(shù),它會創(chuàng)建一個含有3行內(nèi)容的文件,第一行是一個長度超過100KB的行。然后解決main函數(shù)的注釋,嘗試執(zhí)行代碼,會發(fā)現(xiàn)只有一行錯誤信息:

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)
	// 構(gòu)造一個大的單行數(shù)據(jù)
	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("創(chuàng)建文件成功")
}

2.問題探究

讓我們來探究一下這個問題的原因,首先看一下Scan()方法的注釋,這個方法就是每次掃描到下一個token,然后就可以通過獲取字節(jié)或者文本的方法來獲取掃描過的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()函數(shù)是這樣結(jié)合起來使用的,首先Scan()會掃描出一個token,然后Text()將其轉(zhuǎn)成文本(或者其它方法轉(zhuǎn)成字節(jié)),循環(huán)執(zhí)行這種操作就可以按行讀取一個文件。

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

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

3.問題解決

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

這里可以這樣來使用,這個方法不會受到64KB的限制,ReaderString方法會按照指定的定界符來讀取一個完整的行,返回值是字符串和讀取遇到的錯誤。如果想要讀取返回值為字節(jié)的話,可以使用 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)
	}
}

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

ErrBufferFull就是這個緩沖區(qū)溢出錯誤。

我們繼續(xù)進入內(nèi)容其實也可以知道,它默認的緩沖區(qū)大小是4KB。

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。
其中最令人好奇的是第二個參數(shù),它如果是true,則表示當前行沒有讀取完畢,但是緩沖區(qū)滿了,可以看下面這段注釋。

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 // 讀取到文件結(jié)束才退出
		}
		// 讀取到超長行,即單行超過4k字節(jié),直接寫入文件,不對此行做處理
		if isPrefix {
			fmt.Print(string(bline))
			continue
		}

		fmt.Println(string(bline))
	}
}

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

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

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))
	}
}

總結(jié)

到此這篇關(guān)于Golang如何讀取單行超長的文本的文章就介紹到這了,更多相關(guān)Golang讀取超長文本內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang執(zhí)行cmd命令行的方法

    Golang執(zhí)行cmd命令行的方法

    本文主要介紹了Golang執(zhí)行cmd命令行的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • golang 實現(xiàn)并發(fā)求和

    golang 實現(xiàn)并發(fā)求和

    這篇文章主要介紹了golang 并發(fā)求和的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Golang配置管理庫?Viper的教程詳解

    Golang配置管理庫?Viper的教程詳解

    這篇文章主要介紹了Golang?配置管理庫?Viper,使用?viper?能夠很好的去管理你的配置文件信息,比如數(shù)據(jù)庫的賬號密碼,服務(wù)器監(jiān)聽的端口,你可以通過更改配置文件去更改這些內(nèi)容,而不用定位到那一段代碼上去,提高了開發(fā)效率,需要的朋友可以參考下
    2022-05-05
  • GoFrame?gmap遍歷hashmap?listmap?treemap使用技巧

    GoFrame?gmap遍歷hashmap?listmap?treemap使用技巧

    這篇文章主要為大家介紹了GoFrame?gmap遍歷hashmap?listmap?treemap使用技巧的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • 淺析Go語言中的Range關(guān)鍵字

    淺析Go語言中的Range關(guān)鍵字

    Range是go語言中很獨特的一個關(guān)鍵詞,也相當好用。下面就跟著小編來再聊聊這個Range關(guān)鍵字,有需要的朋友們可以參考借鑒。
    2016-09-09
  • Go語言Zap庫Logger的定制化和封裝使用詳解

    Go語言Zap庫Logger的定制化和封裝使用詳解

    這篇文章主要介紹了Go語言Zap庫Logger的定制化和封裝使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • golang 并發(fā)編程之生產(chǎn)者消費者詳解

    golang 并發(fā)編程之生產(chǎn)者消費者詳解

    這篇文章主要介紹了golang 并發(fā)編程之生產(chǎn)者消費者詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • golang調(diào)用c實現(xiàn)的dll接口細節(jié)分享

    golang調(diào)用c實現(xiàn)的dll接口細節(jié)分享

    這篇文章主要介紹了golang調(diào)用c實現(xiàn)的dll接口細節(jié)分享,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • golang雙鏈表的實現(xiàn)代碼示例

    golang雙鏈表的實現(xiàn)代碼示例

    這篇文章主要介紹了golang雙鏈表的實現(xiàn)代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • go語言中時間戳格式化的方法

    go語言中時間戳格式化的方法

    這篇文章主要介紹了go語言中時間戳格式化的方法,涉及Go語言中time的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03

最新評論