概要

xlsx を使用して Excel のデータ読み込みを行う。

https://github.com/tealeg/xlsx

目次

パッケージのインストール

go get github.com/tealeg/xlsx

※ github.com/tealeg/xlsx/v3 v3.2.0

Excel作成

利用しているパッケージの(xlsx)の特性上、数値の int or float の判別が正確にできない為、1行目に項目名、2行目にデータ型を入力する方式とした。

sample1.xlsx

col1col2col2col3
floatintstringformula
1.231abcabc1.23
4.562defdef4.56
7.893ghighi7.89
field1field2field3field4
intintfloatfloat
141.25.6
252.37.8
363.48.9

ソース作成

package main

import (
    "fmt"
    "errors"
    "github.com/tealeg/xlsx/v3"
)

func ReadSheets(filePath string) (map[string][]map[string]interface{}, error){

    data := make(map[string][]map[string]interface{})

    wb, err := xlsx.OpenFile(filePath)
    if err != nil {
        return data, err
    }

    // シート名の一覧
    for _, sh := range wb.Sheets {
        //sh.Close()
        sheetData, err := ReadSheet(filePath, sh.Name)
        if err != nil {
            return data, nil
        }
        data[sh.Name] = sheetData
    }

    return data, nil
}

func ReadSheet(filePath string, sheetName string) ([]map[string]interface{}, error){

    rows := make([]map[string]interface{}, 0)

    wb, err := xlsx.OpenFile(filePath)
    if err != nil {
        return rows, err
    }

    sh, ok := wb.Sheet[sheetName]
    if !ok {
        return rows, errors.New(fmt.Sprintf("Sheet %s does not exist", sheetName))
    }

    defer sh.Close()

    colNames  := make([]string, 0)
    getColNames := func(c *xlsx.Cell) error {
        value, err := c.FormattedValue()
        if err != nil {
            return err
        }
        colNames = append(colNames, value)
        return nil
    }

    typeNames := make([]string, 0)
    getTypeNames := func(c *xlsx.Cell) error {
        value, err := c.FormattedValue()
        if err != nil {
            return err
        }
        typeNames = append(typeNames, value)
        return nil
    }

    getValues := func(c *xlsx.Cell) error {
        value, err := c.FormattedValue()
        if err != nil {
            return err
        }
        cellNo, rowNo := c.GetCoordinates()
        rowNo = rowNo - 2

        if len(rows) < rowNo + 1 {
            rec := make(map[string]interface{})
            rows = append(rows, rec)
        }

        colname := colNames[cellNo]
        rec := &(rows[rowNo])
        if typeNames[cellNo] == "int" {
            intVal, _ := c.Int64()
            (*rec)[colname] = intVal
        } else if typeNames[cellNo] == "float" {
            floatVal, _ := c.Float()
            (*rec)[colname] = floatVal
        } else {
            (*rec)[colname] = value
        }
        return nil
    }

    for i := 0; i < sh.MaxRow; i++ {
        r, err := sh.Row(i)
        if err != nil {
            break
        }
        if i == 0 {
            r.ForEachCell(getColNames)
        } else if i == 1 {
            r.ForEachCell(getTypeNames)
        } else {
            r.ForEachCell(getValues)
        }
    }

    return rows, nil
}

func main(){

    filePath  := "/path/to/sample1.xlsx"

    data, err := ReadSheets(filePath)
    if err != nil {
        fmt.Printf("Error! %v", err)
        panic(err)
    }

    // 全シート読み込み
    for sheetName, rows := range data {
        fmt.Printf("### %s ###\n", sheetName)
        for i, rec := range rows {
            for colname, colvalue := range rec {
                fmt.Printf("%d, %v: %v\n", i, colname, colvalue)
            }
        }
    }

    // シート名を指定して読み込み
    //rows, err := ReadSheet(filePath, sheetName)
    //for i, rec := range rows {
    //    for colname, colvalue := range rec {
    //        fmt.Printf("%d, %v: %v\n", i, colname, colvalue)
    //    }
    //}
}

動作確認

go run main.go

### Sheet1 ###
0, col2: abc
0, col3: abc1.23
0, col1: 1.23
1, col1: 4.56
1, col2: def
1, col3: def4.56
2, col1: 7.89
2, col2: ghi
2, col3: ghi7.89
### Sheet2 ###
0, field1: 1
0, field2: 4
0, field3: 1.2
0, field4: 5.6
1, field4: 7.8
1, field1: 2
1, field2: 5
1, field3: 2.3
2, field3: 3.4
2, field4: 8.9
2, field1: 3
2, field2: 6

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-01-17 (日) 18:53:09 (1185d)