校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > 淺談Golang是如何讀取文件內容的(7種)

淺談Golang是如何讀取文件內容的(7種)

熱門標簽:福州鐵通自動外呼系統 濮陽自動外呼系統代理 澳門防封電銷卡 智能電銷機器人營銷 賺地圖標注的錢犯法嗎 烏魯木齊人工電銷機器人系統 地圖標注測試 廣東語音外呼系統供應商 長沙ai機器人電銷

本文旨在快速介紹Go標準庫中讀取文件的許多選項。

在Go中(就此而言,大多數底層語言和某些動態語言(如Node))返回字節流。 不將所有內容自動轉換為字符串的好處是,其中之一是避免昂貴的字符串分配,這會增加GC壓力。

為了使本文更加簡單,我將使用string(arrayOfBytes)將bytes數組轉換為字符串。 但是,在發布生產代碼時,不應將其作為一般建議。

1.讀取整個文件到內存中

首先,標準庫提供了多種功能和實用程序來讀取文件數據。我們將從os軟件包中提供的基本情況開始。這意味著兩個先決條件:

  • 該文件必須容納在內存中
  • 我們需要預先知道文件的大小,以便實例化一個足以容納它的緩沖區。

有了os.File對象的句柄,我們可以查詢大小并實例化一個字節列表。

package main


import (
 "os"
 "fmt"
)
func main() {
 file, err := os.Open("filetoread.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 defer file.Close()

 fileinfo, err := file.Stat()
 if err != nil {
 fmt.Println(err)
 return
 }

 filesize := fileinfo.Size()
 buffer := make([]byte, filesize)

 bytesread, err := file.Read(buffer)
 if err != nil {
 fmt.Println(err)
 return
 }
 fmt.Println("bytes read: ", bytesread)
 fmt.Println("bytestream to string: ", string(buffer))
}

2.以塊的形式讀取文件

雖然大多數情況下可以一次讀取文件,但有時我們還是想使用一種更加節省內存的方法。例如,以某種大小的塊讀取文件,處理它們,并重復直到結束。在下面的示例中,使用的緩沖區大小為100字節。

package main


import (
 "io"
 "os"
 "fmt"
)

const BufferSize = 100

func main() {
 
 file, err := os.Open("filetoread.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 defer file.Close()

 buffer := make([]byte, BufferSize)

 for {
 bytesread, err := file.Read(buffer)
 if err != nil {
  if err != io.EOF {
  fmt.Println(err)
  }
  break
 }
 fmt.Println("bytes read: ", bytesread)
 fmt.Println("bytestream to string: ", string(buffer[:bytesread]))
 }
}

與完全讀取文件相比,主要區別在于:

  • 讀取直到獲得EOF標記,因此我們為err == io.EOF添加了特定檢查
  • 我們定義了緩沖區的大小,因此我們可以控制所需的“塊”大小。 如果操作系統正確地將正在讀取的文件緩存起來,則可以在正確使用時提高性能。
  • 如果文件大小不是緩沖區大小的整數倍,則最后一次迭代將僅將剩余字節數添加到緩沖區中,因此調用buffer [:bytesread]。 在正常情況下,bytesread將與緩沖區大小相同。

對于循環的每次迭代,都會更新內部文件指針。 下次讀取時,將返回從文件指針偏移開始直到緩沖區大小的數據。 該指針不是語言的構造,而是操作系統之一。 在Linux上,此指針是要創建的文件描述符的屬性。 所有的read / Read調用(分別在Ruby / Go中)在內部都轉換為系統調用并發送到內核,并且內核管理此指針。

3.并發讀取文件塊

如果我們想加快對上述塊的處理,該怎么辦?一種方法是使用多個go例程!與串行讀取塊相比,我們需要做的另一項工作是我們需要知道每個例程的偏移量。請注意,當目標緩沖區的大小大于剩余的字節數時,ReadAt的行為與Read的行為略有不同。

另請注意,我并沒有限制goroutine的數量,它僅由緩沖區大小來定義。實際上,此數字可能會有上限。

package main

import (
 "fmt"
 "os"
 "sync"
)

const BufferSize = 100

type chunk struct {
 bufsize int
 offset int64
}

func main() {
 
 file, err := os.Open("filetoread.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 defer file.Close()

 fileinfo, err := file.Stat()
 if err != nil {
 fmt.Println(err)
 return
 }

 filesize := int(fileinfo.Size())
 // Number of go routines we need to spawn.
 concurrency := filesize / BufferSize
 // buffer sizes that each of the go routine below should use. ReadAt
 // returns an error if the buffer size is larger than the bytes returned
 // from the file.
 chunksizes := make([]chunk, concurrency)

 // All buffer sizes are the same in the normal case. Offsets depend on the
 // index. Second go routine should start at 100, for example, given our
 // buffer size of 100.
 for i := 0; i  concurrency; i++ {
 chunksizes[i].bufsize = BufferSize
 chunksizes[i].offset = int64(BufferSize * i)
 }

 // check for any left over bytes. Add the residual number of bytes as the
 // the last chunk size.
 if remainder := filesize % BufferSize; remainder != 0 {
 c := chunk{bufsize: remainder, offset: int64(concurrency * BufferSize)}
 concurrency++
 chunksizes = append(chunksizes, c)
 }

 var wg sync.WaitGroup
 wg.Add(concurrency)

 for i := 0; i  concurrency; i++ {
 go func(chunksizes []chunk, i int) {
  defer wg.Done()

  chunk := chunksizes[i]
  buffer := make([]byte, chunk.bufsize)
  bytesread, err := file.ReadAt(buffer, chunk.offset)

  if err != nil {
  fmt.Println(err)
  return
  }

  fmt.Println("bytes read, string(bytestream): ", bytesread)
  fmt.Println("bytestream to string: ", string(buffer))
 }(chunksizes, i)
 }

 wg.Wait()
}

與以前的任何方法相比,這種方法要多得多:

  • 我正在嘗試創建特定數量的Go例程,具體取決于文件大小和緩沖區大小(在本例中為100)。
  • 我們需要一種方法來確保我們正在“等待”所有執行例程。 在此示例中,我使用的是wait group。
  • 在每個例程結束的時候,從內部發出信號,而不是break for循環。因為我們延時調用了wg.Done(),所以在每個例程返回的時候才調用它。

注意:始終檢查返回的字節數,并重新分配輸出緩沖區。

使用Read()讀取文件可以走很長一段路,但是有時您需要更多的便利。Ruby中經常使用的是IO函數,例如each_line,each_char, each_codepoint 等等.通過使用Scanner類型以及bufio軟件包中的關聯函數,我們可以實現類似的目的。

bufio.Scanner類型實現帶有“ split”功能的函數,并基于該功能前進指針。例如,對于每個迭代,內置的bufio.ScanLines拆分函數都會使指針前進,直到下一個換行符為止.

在每個步驟中,該類型還公開用于獲取開始位置和結束位置之間的字節數組/字符串的方法。

package main

import (
 "fmt"
 "os"
 "bufio"
)

const BufferSize = 100

type chunk struct {
 bufsize int
 offset int64
}

func main() {
 file, err := os.Open("filetoread.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 defer file.Close()
 scanner := bufio.NewScanner(file)
 scanner.Split(bufio.ScanLines)

 // Returns a boolean based on whether there's a next instance of `\n`
 // character in the IO stream. This step also advances the internal pointer
 // to the next position (after '\n') if it did find that token.
 for {
 read := scanner.Scan()
 if !read {
  break
  
 }
 fmt.Println("read byte array: ", scanner.Bytes())
 fmt.Println("read string: ", scanner.Text())
 }
 
}

因此,要以這種方式逐行讀取整個文件,可以使用如下所示的內容:

package main

import (
 "bufio"
 "fmt"
 "os"
)

func main() {
 file, err := os.Open("filetoread.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 defer file.Close()

 scanner := bufio.NewScanner(file)
 scanner.Split(bufio.ScanLines)

 // This is our buffer now
 var lines []string

 for scanner.Scan() {
 lines = append(lines, scanner.Text())
 }

 fmt.Println("read lines:")
 for _, line := range lines {
 fmt.Println(line)
 }
}

4.逐字掃描

bufio軟件包包含基本的預定義拆分功能:

  • ScanLines (默認)
  • ScanWords
  • ScanRunes(對于遍歷UTF-8代碼點(而不是字節)非常有用)
  • ScanBytes

因此,要讀取文件并在文件中創建單詞列表,可以使用如下所示的內容:

package main

import (
 "bufio"
 "fmt"
 "os"
)

func main() {
 file, err := os.Open("filetoread.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 defer file.Close()

 scanner := bufio.NewScanner(file)
 scanner.Split(bufio.ScanWords)

 var words []string

 for scanner.Scan() {
 words = append(words, scanner.Text())
 }

 fmt.Println("word list:")
 for _, word := range words {
 fmt.Println(word)
 }
}

ScanBytes拆分函數將提供與早期Read()示例相同的輸出。 兩者之間的主要區別是在掃描程序中,每次需要附加到字節/字符串數組時,動態分配問題。 可以通過諸如將緩沖區預初始化為特定長度的技術來避免這種情況,并且只有在達到前一個限制時才增加大小。 使用與上述相同的示例:

package main

import (
 "bufio"
 "fmt"
 "os"
)

func main() {
 file, err := os.Open("filetoread.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 defer file.Close()

 scanner := bufio.NewScanner(file)
 scanner.Split(bufio.ScanWords)

 // initial size of our wordlist
 bufferSize := 50
 words := make([]string, bufferSize)
 pos := 0

 for scanner.Scan() {
 if err := scanner.Err(); err != nil {
  // This error is a non-EOF error. End the iteration if we encounter
  // an error
  fmt.Println(err)
  break
 }

 words[pos] = scanner.Text()
 pos++

 if pos >= len(words) {
  // expand the buffer by 100 again
  newbuf := make([]string, bufferSize)
  words = append(words, newbuf...)
 }
 }

 fmt.Println("word list:")
 // we are iterating only until the value of "pos" because our buffer size
 // might be more than the number of words because we increase the length by
 // a constant value. Or the scanner loop might've terminated due to an
 // error prematurely. In this case the "pos" contains the index of the last
 // successful update.
 for _, word := range words[:pos] {
 fmt.Println(word)
 }
}

因此,我們最終要進行的切片“增長”操作要少得多,但最終可能要根據緩沖區大小和文件中的單詞數在結尾處留出一些空插槽,這是一個折衷方案。

5.將長字符串拆分為單詞

bufio.NewScanner使用滿足io.Reader接口的類型作為參數,這意味著它將與定義了Read方法的任何類型一起使用。
標準庫中返回reader類型的string實用程序方法之一是strings.NewReader函數。當從字符串中讀取單詞時,我們可以將兩者結合起來:

package main

import (
 "bufio"
 "fmt"
 "strings"
)

func main() {
 longstring := "This is a very long string. Not."
 var words []string
 scanner := bufio.NewScanner(strings.NewReader(longstring))
 scanner.Split(bufio.ScanWords)

 for scanner.Scan() {
 words = append(words, scanner.Text())
 }

 fmt.Println("word list:")
 for _, word := range words {
 fmt.Println(word)
 }
}

6.掃描以逗號分隔的字符串

手動解析CSV文件/字符串通過基本的file.Read()或者Scanner類型是復雜的。因為根據拆分功能bufio.ScanWords,“單詞”被定義為一串由unicode空間界定的符文。讀取各個符文并跟蹤緩沖區的大小和位置(例如在詞法分析中所做的工作)是太多的工作和操作。

但這可以避免。 我們可以定義一個新的拆分函數,該函數讀取字符直到讀者遇到逗號,然后在調用Text()或Bytes()時返回該塊。bufio.SplitFunc函數的函數簽名如下所示:

type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)

為簡單起見,我展示了一個讀取字符串而不是文件的示例。 使用上述簽名的CSV字符串的簡單閱讀器可以是:

package main

import (
 "bufio"
 "bytes"
 "fmt"
 "strings"
)

func main() {
 csvstring := "name, age, occupation"

 // An anonymous function declaration to avoid repeating main()
 ScanCSV := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
 commaidx := bytes.IndexByte(data, ',')
 if commaidx > 0 {
  // we need to return the next position
  buffer := data[:commaidx]
  return commaidx + 1, bytes.TrimSpace(buffer), nil
 }

 // if we are at the end of the string, just return the entire buffer
 if atEOF {
  // but only do that when there is some data. If not, this might mean
  // that we've reached the end of our input CSV string
  if len(data) > 0 {
  return len(data), bytes.TrimSpace(data), nil
  }
 }

 // when 0, nil, nil is returned, this is a signal to the interface to read
 // more data in from the input reader. In this case, this input is our
 // string reader and this pretty much will never occur.
 return 0, nil, nil
 }

 scanner := bufio.NewScanner(strings.NewReader(csvstring))
 scanner.Split(ScanCSV)

 for scanner.Scan() {
 fmt.Println(scanner.Text())
 }
}

7.ioutil

我們已經看到了多種讀取文件的方式.但是,如果您只想將文件讀入緩沖區怎么辦?
ioutil是標準庫中的軟件包,其中包含一些使它成為單行的功能。

讀取整個文件

package main

import (
 "io/ioutil"
 "log"
 "fmt"
)

func main() {
 bytes, err := ioutil.ReadFile("filetoread.txt")
 if err != nil {
 log.Fatal(err)
 }

 fmt.Println("Bytes read: ", len(bytes))
 fmt.Println("String read: ", string(bytes))
}

這更接近我們在高級腳本語言中看到的內容。

讀取文件的整個目錄

不用說,如果您有大文件,請不要運行此腳本

package main

import (
 "io/ioutil"
 "log"
 "fmt"
)

func main() {
 filelist, err := ioutil.ReadDir(".")
 if err != nil {
 log.Fatal(err)
 }
 for _, fileinfo := range filelist {
 if fileinfo.Mode().IsRegular() {
  bytes, err := ioutil.ReadFile(fileinfo.Name())
  if err != nil {
  log.Fatal(err)
  }
  fmt.Println("Bytes read: ", len(bytes))
  fmt.Println("String read: ", string(bytes))
 }
 }
}

參考文獻

go語言讀取文件概述

到此這篇關于淺談Golang是如何讀取文件內容的(7種)的文章就介紹到這了,更多相關Golang讀取文件內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

您可能感興趣的文章:
  • golang文件讀取-按指定BUFF大小讀取方式
  • golang逐行讀取文件的操作
  • Golang 實現分片讀取http超大文件流和并發控制
  • golang 使用 viper 讀取自定義配置文件
  • 如何利用Golang解析讀取Mysql備份文件
  • golang讀取文件的常用方法總結
  • Golang 實現超大文件讀取的兩種方法

標簽:廣西 阿克蘇 太原 西雙版納 德州 貴陽 慶陽 調研邀請

巨人網絡通訊聲明:本文標題《淺談Golang是如何讀取文件內容的(7種)》,本文關鍵詞  淺談,Golang,是,如何,讀取,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《淺談Golang是如何讀取文件內容的(7種)》相關的同類信息!
  • 本頁收集關于淺談Golang是如何讀取文件內容的(7種)的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    在线观看欧美精品| 日日夜夜精品免费视频| 成人午夜视频福利| 国产精品午夜电影| www.99精品| 亚洲综合图片区| 在线观看国产日韩| 日韩精品欧美精品| 久久综合一区二区| 福利一区福利二区| 日韩伦理免费电影| 欧美绝品在线观看成人午夜影视| 日本欧美在线看| 日韩一区二区免费高清| 国产一区二区三区免费观看| 久久久不卡影院| 在线中文字幕一区| 理论片日本一区| 国产精品久久久久天堂| 欧美视频中文一区二区三区在线观看| 日韩—二三区免费观看av| 久久久久久一级片| 色乱码一区二区三区88 | 国产亚洲成aⅴ人片在线观看| 国产成人免费av在线| 亚洲美女精品一区| 日韩欧美综合在线| gogogo免费视频观看亚洲一| 亚洲成在线观看| 欧美精品一区二区三区蜜臀| 色综合天天综合网天天狠天天| 日韩经典一区二区| 国产精品久久久久久久午夜片| 在线亚洲免费视频| 激情综合色丁香一区二区| 亚洲青青青在线视频| 日韩免费看网站| 欧美在线播放高清精品| 国产老妇另类xxxxx| 亚洲无人区一区| 国产免费观看久久| 91麻豆精品国产无毒不卡在线观看 | 高清久久久久久| 日韩av中文字幕一区二区三区| 国产精品美女www爽爽爽| 欧美日韩综合在线免费观看| 粉嫩嫩av羞羞动漫久久久| 免费观看在线色综合| 伊人一区二区三区| 国产精品天天摸av网| 91精品国产综合久久精品麻豆| 9i看片成人免费高清| 国产精选一区二区三区| 日本成人在线电影网| 一区二区三区在线观看欧美| 国产精品色眯眯| 精品国产一区久久| 欧美丰满嫩嫩电影| 在线观看91精品国产入口| av毛片久久久久**hd| 国产米奇在线777精品观看| 久久99久久精品| 51久久夜色精品国产麻豆| 99麻豆久久久国产精品免费| 国内久久精品视频| 麻豆免费看一区二区三区| 亚洲国产aⅴ天堂久久| 亚洲精品福利视频网站| 国产日韩欧美在线一区| 久久蜜桃av一区精品变态类天堂| 欧美一卡二卡在线观看| 欧美三级韩国三级日本三斤| 99麻豆久久久国产精品免费| 高清视频一区二区| 国产suv一区二区三区88区| 国产一区二区三区四| 韩国av一区二区| 精品一区二区三区免费观看| 精品中文字幕一区二区| 麻豆视频一区二区| 久久超碰97中文字幕| 激情综合色丁香一区二区| 国产一区二区视频在线播放| 精品中文字幕一区二区小辣椒| 国产做a爰片久久毛片| 国产精品毛片a∨一区二区三区| 欧美亚洲综合网| 欧美主播一区二区三区| 在线免费av一区| 欧美日韩精品一区二区三区| 欧美高清精品3d| 欧美一级xxx| 欧美大度的电影原声| 久久婷婷久久一区二区三区| 久久久久久99精品| 欧美高清在线一区| 亚洲一区二区偷拍精品| 日韩电影一区二区三区四区| 蜜臀av性久久久久蜜臀aⅴ四虎| 久久99久久久久久久久久久| 国产成人精品午夜视频免费| 91视频免费播放| 欧美午夜免费电影| 日韩精品在线一区二区| 国产精品亲子伦对白| 亚洲永久免费av| 久久精品国产免费| 成人黄色软件下载| 精品污污网站免费看| 精品免费一区二区三区| 国产精品天美传媒沈樵| 午夜精品久久久久久久久| 婷婷综合另类小说色区| 欧美绝品在线观看成人午夜影视| 91麻豆精品国产自产在线观看一区| 久久网这里都是精品| 亚洲一区二区三区四区中文字幕| 免费精品视频在线| 成人h版在线观看| 欧美精品久久99| 国产欧美综合在线| 亚洲1区2区3区视频| 国产成人免费在线视频| 欧美日韩一本到| 久久精品视频免费观看| 婷婷久久综合九色国产成人| 成人性视频免费网站| 91精品国产综合久久香蕉麻豆| 国产欧美精品国产国产专区| 亚洲一区二区三区中文字幕| 成人在线综合网| 日韩欧美在线123| 色一区在线观看| 国产精品一区二区三区乱码 | 欧美三电影在线| 精品欧美一区二区久久| 亚洲老司机在线| 国产电影精品久久禁18| 欧美一区二区三区精品| 亚洲免费三区一区二区| 国产91精品入口| 久久久久久亚洲综合影院红桃| 国产精品卡一卡二| 成人黄页毛片网站| 久久久久免费观看| 国产成人精品影院| 国产午夜亚洲精品午夜鲁丝片 | 蜜臀精品一区二区三区在线观看 | 麻豆精品国产传媒mv男同| 亚洲乱码国产乱码精品精的特点| 91精品国产高清一区二区三区 | 轻轻草成人在线| 色诱视频网站一区| 日韩va欧美va亚洲va久久| 色噜噜久久综合| 亚洲欧美一区二区不卡| 欧美日韩一级视频| 天天射综合影视| 国产情人综合久久777777| 久久精品99国产精品| 精品久久五月天| 色久综合一二码| 99久久久国产精品| 亚洲成人免费电影| 精品国产乱码久久久久久影片| 国产乱色国产精品免费视频| 亚洲一区中文在线| 国产欧美一区二区三区沐欲| www.欧美日韩| 日本美女一区二区三区视频| 精品国产一区二区亚洲人成毛片 | 色综合久久久久久久| 久久国产精品99久久久久久老狼| 中文字幕一区二区日韩精品绯色| 色婷婷av一区二区三区gif| 日本伊人精品一区二区三区观看方式| www国产精品av| 91女厕偷拍女厕偷拍高清| 国产精品久久久久精k8| 国产精品久久久久久久蜜臀 | 日韩影视精彩在线| 国产视频在线观看一区二区三区| 色综合视频在线观看| 东方欧美亚洲色图在线| 精品一区二区三区免费观看| 老司机免费视频一区二区| 日韩国产精品久久久| 亚洲成av人片| 午夜欧美2019年伦理| 亚洲国产日韩精品| 偷拍一区二区三区| 亚洲欧洲av在线| 亚洲人成人一区二区在线观看 | 不卡高清视频专区| 国产91富婆露脸刺激对白| 91在线丨porny丨国产| 884aa四虎影成人精品一区| 欧美军同video69gay| 亚洲精品乱码久久久久久 | 麻豆精品在线播放|