中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang操作TSV文件的方法是什么

發布時間:2023-05-11 16:54:59 來源:億速云 閱讀:102 作者:iii 欄目:開發技術

這篇“Golang操作TSV文件的方法是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Golang操作TSV文件的方法是什么”文章吧。

認識TSV文件

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

TSV文件和CSV文件一樣,非常通用,被大多數平臺或處理軟件支持,但TSV文件采用不可見制表符作為分隔符,被用戶誤用的概率較低,相對CSV容錯性更好。

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

解析為結構體

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

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      // 標題數組
    Reader     *csv.Reader   // 讀取器
    Data       interface{}   // 希望解析為結構體的類型
    ref        reflect.Value // 反射值
    indices    []int // indices is field index list of header array
    structMode bool  // 結構模式,結構體有tsv標簽
    normalize  norm.Form     // 解析UTF8方式
}

定義無標題行的機構函數:

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

帶標題行的解析構造函數:

// 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'

    // 讀取一行,即標題行;函數字符串數組
    headers, err := r.Read()

    if err != nil {
        return nil, err
    }

    // 循環給標題數組賦值
    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
}

與上面無標題行相比,多了解析tsv標簽的邏輯。

下面開始解析每行數據,我們看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
}

上面主要邏輯就是通過反射解析并存儲每行數據,并填充結構體的過程。這里僅考慮了string、bool、Int三種類型,當然我們可以擴展支持更多類型。

下面通過main函數進行測試:

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

}

打開文件,定義結構體對象,然后定義解析器,傳入文件和結構體對象作為參數。解析結果存儲在結構體對象中。

以上就是關于“Golang操作TSV文件的方法是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

屯门区| 陇西县| 惠州市| 杭州市| 元江| 多伦县| 崇信县| 西乌珠穆沁旗| 甘孜县| 嘉荫县| 济宁市| 时尚| 临海市| 柘荣县| 建始县| 株洲市| 通辽市| 翼城县| 屏东县| 墨玉县| 隆化县| 永平县| 宁武县| 唐山市| 黑水县| 铜鼓县| 辽宁省| 武乡县| 旬邑县| 弥渡县| 德安县| 乡城县| 金坛市| 民丰县| 仪征市| 岗巴县| 永和县| 婺源县| 呈贡县| 崇州市| 绥滨县|