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

Golang 實(shí)現(xiàn)超大文件讀取的兩種方法

 更新時(shí)間:2021年04月27日 11:45:17   作者:wuhaung  
這篇文章主要介紹了Golang 實(shí)現(xiàn)超大文件讀取的兩種方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

Golang超大文件讀取的兩個(gè)方案

流處理方式

分片處理

去年的面試中我被問(wèn)到超大文件你怎么處理,這個(gè)問(wèn)題確實(shí)當(dāng)時(shí)沒多想,回來(lái)之后仔細(xì)研究和討論了下這個(gè)問(wèn)題,對(duì)大文件讀取做了一個(gè)分析

比如我們有一個(gè)log文件,運(yùn)行了幾年,有100G之大。按照我們之前的操作可能代碼會(huì)這樣寫:

func ReadFile(filePath string) []byte{
    content, err := ioutil.ReadFile(filePath)
    if err != nil {
        log.Println("Read error")
    }
    return content
} 

上面的代碼讀取幾兆的文件可以,但是如果大于你本身及其內(nèi)存,那就直接翻車了。因?yàn)樯厦娴拇a,是把文件所有的內(nèi)容全部都讀取到內(nèi)存之后返回,幾兆的文件,你內(nèi)存夠大可以處理,但是一旦上幾百兆的文件,就沒那么好處理了。

那么,正確的方法有兩種

第一個(gè)是使用流處理方式代碼如下

func ReadFile(filePath string, handle func(string)) error {
    f, err := os.Open(filePath)
    defer f.Close()
    if err != nil {
        return err
    }
    buf := bufio.NewReader(f)
 
    for {
        line, err := buf.ReadLine("\n")
        line = strings.TrimSpace(line)
        handle(line)
        if err != nil {
            if err == io.EOF{
                return nil
            }
            return err
        }
        return nil
    }
}

第二個(gè)方案就是分片處理

當(dāng)讀取的是二進(jìn)制文件,沒有換行符的時(shí)候,使用下面的方案一樣處理大文件

func ReadBigFile(fileName string, handle func([]byte)) error {
    f, err := os.Open(fileName)
    if err != nil {
        fmt.Println("can't opened this file")
        return err
    }
    defer f.Close()
    s := make([]byte, 4096)
    for {
        switch nr, err := f.Read(s[:]); true {
        case nr < 0:
            fmt.Fprintf(os.Stderr, "cat: error reading: %s\n

補(bǔ)充:golang 讀取大文件處理sync.pool + bufio.NewReader(f)

看代碼吧~

文件大小

在這里插入圖片描述

package main
import (
	"bufio"
	"fmt"
	"io"
	//"math"
	"os"
	"strings"
	"sync"
	"time"
)
func main() {
	/*
	文件數(shù)據(jù)樣例
	{"remark": "來(lái)電時(shí)間:  2021/04/15 13:52:07客戶電話:13913xx39xx ", "no": "600020510132021101310210547639", "title": "b-ae0e-0242ac100907", "call_in_date": "2021-04-15 13:52:12", "name": "張三", "_date": "2021-06-15", "name": "張三", "meet": "1"}
	1、我們?nèi)〕?call_in_date": "2021-04-15 13:52:1的數(shù)據(jù)寫入另一個(gè)文件
	*/
	var (
		s time.Time //當(dāng)前時(shí)間
		file *os.File
		fileStat os.FileInfo
		err error
		lastLineSize int64
	)
	s = time.Now()
	if file, err = os.Open("/Users/zhangsan/Downloads/log.txt");err != nil{
		fmt.Println(err)
	}
	defer func() {
		err = file.Close() //close after checking err
	}()
	//queryStartTime, err := time.Parse("2006-01-02T15:04:05.0000Z", startTimeArg)
	//if err != nil {
	//	fmt.Println("Could not able to parse the start time", startTimeArg)
	//	return
	//}
	//
	//queryFinishTime, err := time.Parse("2006-01-02T15:04:05.0000Z", finishTimeArg)
	//if err != nil {
	//	fmt.Println("Could not able to parse the finish time", finishTimeArg)
	//	return
	//}
	/**
	* {name:"log.log", size:911100961, mode:0x1a4,
	modTime:time.Time{wall:0x656c25c, ext:63742660691,
	loc:(*time.Location)(0x1192c80)}, sys:syscall.Stat_t{Dev:16777220,
	Mode:0x81a4, Nlink:0x1, Ino:0x118cba7, Uid:0x1f5, Gid:0x14, Rdev:0,
	Pad_cgo_0:[4]uint8{0x0, 0x0, 0x0, 0x0}, Atimespec:syscall.Timespec{Sec:1607063899, Nsec:977970393},
	Mtimespec:syscall.Timespec{Sec:1607063891, Nsec:106349148}, Ctimespec:syscall.Timespec{Sec:1607063891,
	Nsec:258847043}, Birthtimespec:syscall.Timespec{Sec:1607063883, Nsec:425808150},
	Size:911100961, Blocks:1784104, Blksize:4096, Flags:0x0, Gen:0x0, Lspare:0, Qspare:[2]int64{0, 0}}
	*
	*/
	if fileStat, err = file.Stat();err != nil {
		return
	}
	fileSize := fileStat.Size()//72849354767
	offset := fileSize - 1
	//檢測(cè)是不是都是空行 只有\(zhòng)n
	for {
		var (
			b []byte
			n int
			char string
		)
		b = make([]byte, 1)
		//從指定位置讀取
		if n, err = file.ReadAt(b, offset);err != nil {
			fmt.Println("Error reading file ", err)
			break
		}
		char = string(b[0])
		if char == "\n" {
			break
		}
		offset--
		//獲取一行的大小
		lastLineSize += int64(n)
	}
	var (
		lastLine []byte
		logSlice []string
		logSlice1 []string
	)
	//初始化一行大小的空間
	lastLine = make([]byte, lastLineSize)
	_, err = file.ReadAt(lastLine, offset)
	if err != nil {
		fmt.Println("Could not able to read last line with offset", offset, "and lastline size", lastLineSize)
		return
	}
	//根據(jù)條件進(jìn)行區(qū)分
	logSlice = strings.Split(strings.Trim(string(lastLine),"\n"),"next_pay_date")
	logSlice1  = strings.Split(logSlice[1],"\"")
	if logSlice1[2] == "2021-06-15"{
		Process(file)
	}
	fmt.Println("\nTime taken - ", time.Since(s))
		fmt.Println(err)
}
func Process(f *os.File) error {
	//讀取數(shù)據(jù)的key,減小gc壓力
	linesPool := sync.Pool{New: func() interface{} {
		lines := make([]byte, 250*1024)
		return lines
	}}
	//讀取回來(lái)的數(shù)據(jù)池
	stringPool := sync.Pool{New: func() interface{} {
		lines := ""
		return lines
	}}
	//一個(gè)文件對(duì)象本身是實(shí)現(xiàn)了io.Reader的 使用bufio.NewReader去初始化一個(gè)Reader對(duì)象,存在buffer中的,讀取一次就會(huì)被清空
	r := bufio.NewReader(f) //
	//設(shè)置讀取緩沖池大小 默認(rèn)16
	r = bufio.NewReaderSize(r,250 *1024)
	var wg sync.WaitGroup
	for {
		buf := linesPool.Get().([]byte)
		//讀取Reader對(duì)象中的內(nèi)容到[]byte類型的buf中
		n, err := r.Read(buf)
		buf = buf[:n]
		if n == 0 {
			if err != nil {
				fmt.Println(err)
				break
			}
			if err == io.EOF {
				break
			}
			return err
		}
		//補(bǔ)齊剩下沒滿足的剩余
		nextUntillNewline, err := r.ReadBytes('\n')
		//fmt.Println(string(nextUntillNewline))
		if err != io.EOF {
			buf = append(buf, nextUntillNewline...)
		}
		wg.Add(1)
		go func() {
			ProcessChunk(buf, &linesPool, &stringPool)
			wg.Done()
		}()
	}
	wg.Wait()
	return nil
}
func ProcessChunk(chunk []byte, linesPool *sync.Pool,stringPool *sync.Pool) {
//做相應(yīng)的處理
}

執(zhí)行

go run test2.go "2020-01-01T00:00:00.0000Z" "2020-02-02T00:00:00.0000Z" /Users/zhangsan/go/src/workspace/test/log.log
EOF
Time taken -  20.023517675s
<nil>

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • Go?語(yǔ)言結(jié)構(gòu)體鏈表的基本操作

    Go?語(yǔ)言結(jié)構(gòu)體鏈表的基本操作

    鏈表是一種物理存儲(chǔ)單元上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過(guò)鏈表中的指針鏈接次序?qū)崿F(xiàn)的,這篇文章主要介紹了Go?語(yǔ)言結(jié)構(gòu)體鏈表,需要的朋友可以參考下
    2022-04-04
  • Go語(yǔ)言中接口組合的實(shí)現(xiàn)方法

    Go語(yǔ)言中接口組合的實(shí)現(xiàn)方法

    這篇文章主要介紹了Go語(yǔ)言中接口組合的實(shí)現(xiàn)方法,實(shí)例分析了接口中包含接口的實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2015-02-02
  • Golang中多個(gè)if代碼優(yōu)化小技巧

    Golang中多個(gè)if代碼優(yōu)化小技巧

    這篇文章主要為大家詳細(xì)介紹了Golang中一些常用的if代碼優(yōu)化小技巧,w文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • Golang使用Gin框架實(shí)現(xiàn)HTTP響應(yīng)格式統(tǒng)一處理

    Golang使用Gin框架實(shí)現(xiàn)HTTP響應(yīng)格式統(tǒng)一處理

    在gin框架中,我們可以定義一個(gè)中間件來(lái)處理統(tǒng)一的HTTP響應(yīng)格式,本文主要為大家介紹了具體是怎么定義實(shí)現(xiàn)這樣的中間件的,感興趣的小伙伴可以了解一下
    2023-07-07
  • goland 實(shí)現(xiàn)自動(dòng)格式化代碼

    goland 實(shí)現(xiàn)自動(dòng)格式化代碼

    這篇文章主要介紹了goland 實(shí)現(xiàn)自動(dòng)格式化代碼的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • golang實(shí)現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作

    golang實(shí)現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作

    這篇文章主要介紹了golang實(shí)現(xiàn)整型和字節(jié)數(shù)組之間的轉(zhuǎn)換操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 在goland中配置gofmt的操作

    在goland中配置gofmt的操作

    這篇文章主要介紹了在goland中配置gofmt的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go 中燒腦的接口及空接口

    Go 中燒腦的接口及空接口

    在Go語(yǔ)言的實(shí)際編程中,幾乎所有的數(shù)據(jù)結(jié)構(gòu)都圍繞接口展開,接口是Go語(yǔ)言中所有數(shù)據(jù)結(jié)構(gòu)的核心,這篇文章主要介紹了Go 中燒腦的接口,需要的朋友可以參考下
    2024-02-02
  • Go?跨域中間件解決CORS問(wèn)題

    Go?跨域中間件解決CORS問(wèn)題

    跨域問(wèn)題CORS是前端開發(fā)人員經(jīng)常遇到的問(wèn)題,本文主要介紹了Go?跨域中間件解決CORS問(wèn)題,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-04-04
  • Golang中正則表達(dá)式語(yǔ)法及相關(guān)示例

    Golang中正則表達(dá)式語(yǔ)法及相關(guān)示例

    正則表達(dá)式是一種用于匹配和操作文本的強(qiáng)大工具,它使用特殊的字符和語(yǔ)法來(lái)定義模式,下面這篇文章主要給大家介紹了關(guān)于Golang中正則表達(dá)式語(yǔ)法及相關(guān)示例的相關(guān)資料,需要的朋友可以參考下
    2024-05-05

最新評(píng)論

紫阳县| 汤原县| 高碑店市| 潮安县| 镇安县| 桑日县| 庄河市| 思茅市| 余干县| 崇礼县| 云南省| 上高县| 内丘县| 三明市| 黄平县| 宿松县| 沅江市| 永济市| 尚志市| 泰顺县| 蓬溪县| 德保县| 江安县| 邵阳县| 高州市| 广昌县| 宁安市| 中卫市| 达州市| 宁国市| 鲜城| 札达县| 托克逊县| 彰化县| 安岳县| 婺源县| 兰州市| 连云港市| 微博| 九江县| 两当县|