最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言:

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

1.問題復現(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.問題解決

其實大部分情況下我們都應該使用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打印輸出的。

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

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的函數(shù)特性

    一文詳解Golang的函數(shù)特性

    函數(shù)是?Golang?中非常重要的組成部分之一,它們提供了代碼的可重用性和組織性。在本文中,我們將深入了解?Golang?函數(shù)的多個方面,希望對大家有所幫助
    2023-04-04
  • Go?錯誤處理實踐總結(jié)示例

    Go?錯誤處理實踐總結(jié)示例

    這篇文章主要為大家介紹了Go錯誤處理實踐的總結(jié)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 利用Golang如何調(diào)用Linux命令詳解

    利用Golang如何調(diào)用Linux命令詳解

    這篇文章主要給大家介紹了Golang中使用os/exec來執(zhí)行 Linux 命令的相關(guān)資料,文中給出了詳細的示例代碼,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-05-05
  • GoLang讀取文件的10種方法實例

    GoLang讀取文件的10種方法實例

    讀取文件是所有編程語言中最常見的操作之一,下面這篇文章主要給大家介紹了關(guān)于GoLang讀取文件的10種方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-06-06
  • go語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。
    2015-03-03
  • Go語言繼承功能使用結(jié)構(gòu)體實現(xiàn)代碼重用

    Go語言繼承功能使用結(jié)構(gòu)體實現(xiàn)代碼重用

    今天我來給大家介紹一下在?Go?語言中如何實現(xiàn)類似于繼承的功能,讓我們的代碼更加簡潔和可重用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • golang實現(xiàn)redis的延時消息隊列功能示例

    golang實現(xiàn)redis的延時消息隊列功能示例

    這篇文章主要介紹了golang實現(xiàn)redis的延時消息隊列功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • go語言日志記錄庫簡單使用方法實例分析

    go語言日志記錄庫簡單使用方法實例分析

    這篇文章主要介紹了go語言日志記錄庫簡單使用方法,實例分析了Go語言日志記錄的操作的技巧,需要的朋友可以參考下
    2015-03-03
  • Golang中重復錯誤處理的優(yōu)化方法

    Golang中重復錯誤處理的優(yōu)化方法

    這篇文章主要給大家介紹了關(guān)于Golang中重復錯誤處理優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Golang具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04
  • Golang通脈之類型定義

    Golang通脈之類型定義

    這篇文章主要介紹了Golang通脈之類型定義,在Go語言中有一些基本的數(shù)據(jù)類型,如 string 、 整型 、 浮點型 、 布爾 等數(shù)據(jù)類型, Go語言中可以使用 type 關(guān)鍵字來定義自定義類型,下面和小編一起進入文章看具體內(nèi)容吧
    2021-10-10

最新評論

耒阳市| 会同县| 金门县| 若羌县| 瑞昌市| 天台县| 怀宁县| 武安市| 甘肃省| 高州市| 长宁县| 卢氏县| 茶陵县| 英德市| 东平县| 江陵县| 肥城市| 湘西| 彩票| 滕州市| 耿马| 古浪县| 革吉县| 舞钢市| 珲春市| 泰顺县| 河北区| 利津县| 资阳市| 苗栗市| 泰和县| 荣昌县| 宜兰县| 临朐县| 南丰县| 武鸣县| 织金县| 新龙县| 疏附县| 麟游县| 治多县|