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

Golang 操作TSV文件的實(shí)戰(zhàn)示例

 更新時(shí)間:2023年03月22日 16:24:59   作者:夢(mèng)想畫家  
本文主要介紹了Golang 操作TSV文件的實(shí)戰(zhàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

本文介紹TSV文件類型及其應(yīng)用,同時(shí)介紹Golang語(yǔ)句讀取TSV文件并轉(zhuǎn)為struct的實(shí)現(xiàn)過(guò)程。

認(rèn)識(shí)TSV文件

也許你之前不了解TSV文件,無(wú)需擔(dān)心,它很簡(jiǎn)單、很常用。TSV(tab-separated values)文件表示以tab分割值的文件格式,也就是說(shuō),TSV文件包括一系列數(shù)據(jù)信息,其中數(shù)據(jù)使用tab符(也稱制表符,\t)進(jìn)行分割。與CSV文件格式類似,CSV使用半角逗號(hào)(,)分割。

TSV文件和CSV文件一樣,非常通用,被大多數(shù)平臺(tái)或處理軟件支持,但TSV文件采用不可見(jiàn)制表符作為分隔符,被用戶誤用的概率較低,相對(duì)CSV容錯(cuò)性更好。

Golang 讀取TSV文件

golang 包encoding/csv提供了csv文件的讀寫功能,我們值得tsv和csv的差異僅為分隔符,因此下面代碼可以很容易讀取tsv:

package main

import (
? ? "encoding/csv"
? ? "fmt"
? ? "log"
? ? "os"
)

func main() {

? ? f, err := os.Open("users.csv")

? ? if err != nil {

? ? ? ? log.Fatal(err)
? ? }

? ? r := csv.NewReader(f)
? ? r.Comma = '\t'
? ? r.Comment = '#'

? ? records, err := r.ReadAll()

? ? if err != nil {
? ? ? ? log.Fatal(err)
? ? }

? ? fmt.Print(records)
}

解析為結(jié)構(gòu)體

一般我們希望讀取tsv文件并解析為struct,下面一起看一些開源代碼實(shí)現(xiàn)。tsv文件可能包括標(biāo)題行,同時(shí)字段增加tsv標(biāo)簽,示例如下:

type TestTaggedRow struct {
    Age    int    `tsv:"age"`
    Active bool   `tsv:"active"`
    Gender string `tsv:"gender"`
    Name   string `tsv:"name"`
}

因此定義Parse類型:

// Parser has information for parser
type Parser struct {
    Headers    []string      // 標(biāo)題數(shù)組
    Reader     *csv.Reader   // 讀取器
    Data       interface{}   // 希望解析為結(jié)構(gòu)體的類型
    ref        reflect.Value // 反射值
    indices    []int // indices is field index list of header array
    structMode bool  // 結(jié)構(gòu)模式,結(jié)構(gòu)體有tsv標(biāo)簽
    normalize  norm.Form     // 解析UTF8方式
}

定義無(wú)標(biāo)題行的機(jī)構(gòu)函數(shù):

// NewParserWithoutHeader creates new TSV parser with given io.Reader
func NewParserWithoutHeader(reader io.Reader, data interface{}) *Parser {
?? ?r := csv.NewReader(reader)
?? ?r.Comma = '\t'

?? ?p := &Parser{
?? ??? ?Reader: ? ?r,
?? ??? ?Data: ? ? ?data,
?? ??? ?ref: ? ? ? reflect.ValueOf(data).Elem(),
?? ??? ?normalize: -1,
?? ?}

?? ?return p
}

帶標(biāo)題行的解析構(gòu)造函數(shù):

// NewStructModeParser creates new TSV parser with given io.Reader as struct mode
func NewParser(reader io.Reader, data interface{}) (*Parser, error) {
?? ?r := csv.NewReader(reader)
?? ?r.Comma = '\t'

?? ?// 讀取一行,即標(biāo)題行;函數(shù)字符串?dāng)?shù)組
?? ?headers, err := r.Read()

?? ?if err != nil {
?? ??? ?return nil, err
?? ?}

? ? // 循環(huán)給標(biāo)題數(shù)組賦值
?? ?for i, header := range headers {
?? ??? ?headers[i] = header
?? ?}

?? ?p := &Parser{
?? ??? ?Reader: ? ? r,
?? ??? ?Headers: ? ?headers,
?? ??? ?Data: ? ? ? data,
?? ??? ?ref: ? ? ? ?reflect.ValueOf(data).Elem(),
?? ??? ?indices: ? ?make([]int, len(headers)),
?? ??? ?structMode: false,
?? ??? ?normalize: ?-1,
?? ?}

?? ?// get type information
?? ?t := p.ref.Type()

?? ?for i := 0; i < t.NumField(); i++ {
?? ??? ?// get TSV tag
?? ??? ?tsvtag := t.Field(i).Tag.Get("tsv")
?? ??? ?if tsvtag != "" {
?? ??? ??? ?// find tsv position by header
?? ??? ??? ?for j := 0; j < len(headers); j++ {
?? ??? ??? ??? ?if headers[j] == tsvtag {
?? ??? ??? ??? ??? ?// indices are 1 start
?? ??? ??? ??? ??? ?p.indices[j] = i + 1
?? ??? ??? ??? ??? ?p.structMode = true
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ?}

?? ?if !p.structMode {
?? ??? ?for i := 0; i < len(headers); i++ {
?? ??? ??? ?p.indices[i] = i + 1
?? ??? ?}
?? ?}

?? ?return p, nil
}

與上面無(wú)標(biāo)題行相比,多了解析tsv標(biāo)簽的邏輯。

下面開始解析每行數(shù)據(jù),我們看Next()方法:

// Next puts reader forward by a line
func (p *Parser) Next() (eof bool, err error) {

?? ?// Get next record
?? ?var records []string

?? ?for {
?? ??? ?// read until valid record
?? ??? ?records, err = p.Reader.Read()
?? ??? ?if err != nil {
?? ??? ??? ?if err.Error() == "EOF" {
?? ??? ??? ??? ?return true, nil
?? ??? ??? ?}
?? ??? ??? ?return false, err
?? ??? ?}
?? ??? ?if len(records) > 0 {
?? ??? ??? ?break
?? ??? ?}
?? ?}

?? ?if len(p.indices) == 0 {
?? ??? ?p.indices = make([]int, len(records))
?? ??? ?// mapping simple index
?? ??? ?for i := 0; i < len(records); i++ {
?? ??? ??? ?p.indices[i] = i + 1
?? ??? ?}
?? ?}

?? ?// record should be a pointer
?? ?for i, record := range records {
?? ??? ?idx := p.indices[i]
?? ??? ?if idx == 0 {
?? ??? ??? ?// skip empty index
?? ??? ??? ?continue
?? ??? ?}
?? ??? ?// get target field
?? ??? ?field := p.ref.Field(idx - 1)
?? ??? ?switch field.Kind() {
?? ??? ?case reflect.String:
?? ??? ??? ?// Normalize text
?? ??? ??? ?if p.normalize >= 0 {
?? ??? ??? ??? ?record = p.normalize.String(record)
?? ??? ??? ?}
?? ??? ??? ?field.SetString(record)
?? ??? ?case reflect.Bool:
?? ??? ??? ?if record == "" {
?? ??? ??? ??? ?field.SetBool(false)
?? ??? ??? ?} else {
?? ??? ??? ??? ?col, err := strconv.ParseBool(record)
?? ??? ??? ??? ?if err != nil {
?? ??? ??? ??? ??? ?return false, err
?? ??? ??? ??? ?}
?? ??? ??? ??? ?field.SetBool(col)
?? ??? ??? ?}
?? ??? ?case reflect.Int:
?? ??? ??? ?if record == "" {
?? ??? ??? ??? ?field.SetInt(0)
?? ??? ??? ?} else {
?? ??? ??? ??? ?col, err := strconv.ParseInt(record, 10, 0)
?? ??? ??? ??? ?if err != nil {
?? ??? ??? ??? ??? ?return false, err
?? ??? ??? ??? ?}
?? ??? ??? ??? ?field.SetInt(col)
?? ??? ??? ?}
?? ??? ?default:
?? ??? ??? ?return false, errors.New("Unsupported field type")
?? ??? ?}
?? ?}

?? ?return false, nil
}

上面主要邏輯就是通過(guò)反射解析并存儲(chǔ)每行數(shù)據(jù),并填充結(jié)構(gòu)體的過(guò)程。這里僅考慮了string、bool、Int三種類型,當(dāng)然我們可以擴(kuò)展支持更多類型。

下面通過(guò)main函數(shù)進(jìn)行測(cè)試:

import (
? ? "fmt"
? ? "os"
? ? )

type TestRow struct {
? Name ? string // 0
? Age ? ?int ? ?// 1
? Gender string // 2
? Active bool ? // 3
}

func main() {

? file, _ := os.Open("example.tsv")
? defer file.Close()

? data := TestRow{}
? parser, _ := NewParser(file, &data)

? for {
? ? eof, err := parser.Next()
? ? if eof {
? ? ? return
? ? }
? ? if err != nil {
? ? ? panic(err)
? ? }
? ? fmt.Println(data)
? }

}

打開文件,定義結(jié)構(gòu)體對(duì)象,然后定義解析器,傳入文件和結(jié)構(gòu)體對(duì)象作為參數(shù)。解析結(jié)果存儲(chǔ)在結(jié)構(gòu)體對(duì)象中。上面代碼參考tsv開源項(xiàng)目:https://github.com/dogenzaka/tsv。還有咱們更強(qiáng)大的開源庫(kù):https://github.com/shenwei356/csvtk,不僅解析CSV/TSV文件,還能實(shí)現(xiàn)不同格式的轉(zhuǎn)換。

到此這篇關(guān)于Golang 操作TSV文件的實(shí)戰(zhàn)示例的文章就介紹到這了,更多相關(guān)Golang 操作TSV文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 在Golang中使用C語(yǔ)言代碼實(shí)例

    在Golang中使用C語(yǔ)言代碼實(shí)例

    這篇文章主要介紹了在Golang中使用C語(yǔ)言代碼實(shí)例,本文先是給出了一個(gè)Hello World例子、Golang 引用 C例子,并總結(jié)了一些要注意的地方,需要的朋友可以參考下
    2014-10-10
  • golang微服務(wù)框架基礎(chǔ)Gin基本路由使用詳解

    golang微服務(wù)框架基礎(chǔ)Gin基本路由使用詳解

    這篇文章主要為大家介紹了golang微服務(wù)框架Gin基本路由的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • golang 實(shí)現(xiàn)一個(gè)負(fù)載均衡案例(隨機(jī),輪訓(xùn))

    golang 實(shí)現(xiàn)一個(gè)負(fù)載均衡案例(隨機(jī),輪訓(xùn))

    這篇文章主要介紹了golang 實(shí)現(xiàn)一個(gè)負(fù)載均衡案例(隨機(jī)、輪訓(xùn)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • go如何刪除字符串中的部分字符

    go如何刪除字符串中的部分字符

    這篇文章主要介紹了go刪除字符串中的部分字符操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Golang語(yǔ)言實(shí)現(xiàn)gRPC的具體使用

    Golang語(yǔ)言實(shí)現(xiàn)gRPC的具體使用

    本文主要介紹了Golang語(yǔ)言實(shí)現(xiàn)gRPC的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • golang標(biāo)準(zhǔn)庫(kù)time時(shí)間包的使用

    golang標(biāo)準(zhǔn)庫(kù)time時(shí)間包的使用

    時(shí)間和日期是我們編程中經(jīng)常會(huì)用到的,本文主要介紹了golang標(biāo)準(zhǔn)庫(kù)time時(shí)間包的使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • go gin中間件關(guān)于 c.next()、c.abort()和return的使用小結(jié)

    go gin中間件關(guān)于 c.next()、c.abort()和return的使用小結(jié)

    中間件的執(zhí)行順序是按照注冊(cè)順序執(zhí)行的,中間件可以通過(guò) c.abort() + retrurn 來(lái)中止當(dāng)前中間件,后續(xù)中間件和處理器的處理流程,?這篇文章給大家介紹go gin中間件關(guān)于 c.next()、c.abort()和return的使用小結(jié),感興趣的朋友跟隨小編一起看看吧
    2024-03-03
  • go語(yǔ)言限制協(xié)程并發(fā)數(shù)的方案詳情

    go語(yǔ)言限制協(xié)程并發(fā)數(shù)的方案詳情

    一個(gè)線程中可以有任意多個(gè)協(xié)程,但某一時(shí)刻只能有一個(gè)協(xié)程在運(yùn)行,多個(gè)協(xié)程分享該線程分配到的計(jì)算機(jī)資源,接下來(lái)通過(guò)本文給大家介紹go語(yǔ)言限制協(xié)程的并發(fā)數(shù)的方案詳情,感興趣的朋友一起看看吧
    2022-01-01
  • Goland中Protobuf的安裝、配置和使用

    Goland中Protobuf的安裝、配置和使用

    本文記錄了mac環(huán)境下protobuf的編譯安裝,并通過(guò)一個(gè)示例來(lái)演示proto自動(dòng)生成go代碼,本文使用的mac?os?12.3系統(tǒng),不建議使用homebrew安裝,系統(tǒng)版本太高,會(huì)安裝報(bào)錯(cuò),所以自己下載新版壓縮包編譯構(gòu)建安裝
    2022-05-05
  • Golang實(shí)現(xiàn)單元測(cè)試中的邏輯層

    Golang實(shí)現(xiàn)單元測(cè)試中的邏輯層

    前面我們完成了最麻煩的數(shù)據(jù)層的單元測(cè)試,今天我們來(lái)看看單元測(cè)試中最容易做的一層,數(shù)據(jù)邏輯層,也就是我們通常說(shuō)的 service 或者 biz 等
    2023-03-03

最新評(píng)論

湾仔区| 平度市| 北辰区| 高邮市| 岳阳市| 平塘县| 开原市| 连州市| 正阳县| 宁晋县| 泰顺县| 铜山县| 永仁县| 闸北区| 益阳市| 拉萨市| 正镶白旗| 泸水县| 勐海县| 南丰县| 章丘市| 巴彦县| 苗栗县| 望都县| 星子县| 浮梁县| 通山县| 武义县| 阿克苏市| 元江| 德惠市| 贵州省| 外汇| 天门市| 延边| 凤山市| 宁蒗| 平舆县| 华亭县| 瑞金市| 河源市|