您好,登錄后才能下訂單哦!
這篇“Golang操作TSV文件的方法是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Golang操作TSV文件的方法是什么”文章吧。
也許你之前不了解TSV文件,無需擔心,它很簡單、很常用。TSV(tab-separated values)文件表示以tab分割值的文件格式,也就是說,TSV文件包括一系列數據信息,其中數據使用tab符(也稱制表符,\t)進行分割。與CSV文件格式類似,CSV使用半角逗號(,)分割。
TSV文件和CSV文件一樣,非常通用,被大多數平臺或處理軟件支持,但TSV文件采用不可見制表符作為分隔符,被用戶誤用的概率較低,相對CSV容錯性更好。
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文件的方法是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。