💱

【Golang】ExcelizeでExcelファイルを簡単操作!

7 min read

はじめに

MicrosoftExcelファイル(以後、Excelという)は、切っても切れない関係ですよね。
OpenOfficeGoogle スプレッドシートNumbers は、いずれもExcelとの互換性を保っています。

互換性を保っているということは、脱Excelが非常に難しくユーザーから互換機能を求められていると思います。
今回はExcelizeを使ったExcelファイル操作が簡単なので利用方法についてまとめてみます!

開発環境

  • go (1.14.2)
  • Excelize

Excelizeとは

Excelizeは、純粋なGoで記述されたライブラリです。
MicrosoftExcelファイル(以後、Excelという)の読み取り、書き込み、書式設定などをサポートしています。
Excelizeを使うとExcel操作がめちゃくちゃ簡単なのでオススメです!

詳しくはこちらを公式を参照してください。

https://github.com/qax-os/excelize

インストール

go.modを利用しているため、以下の手順で行います。

go mod init hoge

すると、「go.mod」ファイルが出来ています。

go.mod

module hoge

go 1.16

Excelizeの公式にある通り、Go Modulesを利用している場合は以下のコマンドを実行します。

go get github.com/xuri/excelize/v2  
go get github.com/360EntSecGroup-Skylar/excelize

go.mod

module hoge

go 1.16

require (
	github.com/360EntSecGroup-Skylar/excelize v1.4.1 // indirect
	github.com/xuri/excelize/v2 v2.4.1 // indirect
)

これで準備は整いました!早速やってみましょう!

やってみよう

作成したExcelファイルの結果は全てNumbersでの表示になります。
またimportは省略してます。

ファイル作成

package main

import (
	"fmt"

	"github.com/360EntSecGroup-Skylar/excelize"
)

func main() {
	f := excelize.NewFile()

	if err := f.SaveAs("サンプル.xlsx"); err != nil {
		fmt.Println(err)
	}
}

これだけでExcelファイルが作成出来てしまいます!めちゃくちゃ簡単…。

読み込み

  • 直接ファイル名を読み込む場合
package main

import (
	"fmt"

	"github.com/360EntSecGroup-Skylar/excelize"
)

func main() {
	f, err := excelize.OpenFile("ExcelizeSample.xlsx")
	if err != nil {
		fmt.Println(err)
		return
	}
	// 1番目シート名を取得しています
	fmt.Println(f.GetSheetName(1))
}
  • バイナリファイルを読み込む場合
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"

	"github.com/360EntSecGroup-Skylar/excelize"
)

func main() {
	b, err := ioutil.ReadFile("ExcelizeSample.xlsx")
	if err != nil {
		fmt.Println(err)
		return
	}
	f, err := excelize.OpenReader(bytes.NewReader(b))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(f.GetSheetName(1))
}

シート操作

package main

import (
	"fmt"

	"github.com/360EntSecGroup-Skylar/excelize"
)

func main() {
	f := excelize.NewFile()

	// シート名変更
	changeSheetName := "サンプル"
	f.SetSheetName("Sheet1", changeSheetName)

	// A1セルに値を設定
	f.SetCellValue(changeSheetName, "A1", 123)

	// シート追加
	addSheetName := "サンプル2"
	i := f.NewSheet(addSheetName)

	// シート名取得 => サンプル2 と出力される
	fmt.Println(f.GetSheetName(i))

	// シート削除
	deleteSheetName := "サンプル3"
	f.NewSheet(deleteSheetName)
	f.DeleteSheet(deleteSheetName)

	// シートコピー
	from := f.GetSheetIndex(changeSheetName)
	to := f.GetSheetIndex(addSheetName)
	if err := f.CopySheet(from, to); err != nil {
		fmt.Println(err)
		return
	}

	if err := f.SaveAs("サンプル.xlsx"); err != nil {
		fmt.Println(err)
		return
	}
}
  • 出力結果

サンプル以外にも、シートを表示/非表示にしたり、シート内を検索出来るので多機能です。

セル操作

Excelizeで画像を扱う場合は、必要に応じて以下のimportを行ってください。

  • _ "image/gif"
  • _ "image/jepg"
  • _ "image/png"
package main

import (
	"bytes"
	"fmt"
	"image/png"
	"os"

	"github.com/xuri/excelize/v2"
)

func main() {
	f := excelize.NewFile()

	// シート名変更
	changeSheetName := "サンプル"
	f.SetSheetName("Sheet1", changeSheetName)

	// セルに値を設定
	// SetCellBool, SetCellInt, SetCellStrなどがありますが、SetCellValueがinterface型なので使いやすいかなと思います
	f.SetCellValue(changeSheetName, "A1", 123)
	f.SetCellValue(changeSheetName, "A2", true)
	f.SetCellValue(changeSheetName, "A3", "123")

	// 計算式
	f.SetCellValue(changeSheetName, "B1", 123)
	f.SetCellValue(changeSheetName, "B2", 123)
	f.SetCellFormula(changeSheetName, "B3", "B1+B2")

	// スタイル設定(フォント)
	// github.com/360EntSecGroup-Skylar/excelize を使う場合は、下記のように文字列で書く必要があります。
	// style, err := f.NewStyle(`{"font":{"bold":true,"italic":true,"family":"Berlin Sans FB Demi","size":36,"color":"#777777"}}`)
	style, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Bold:   true,
			Italic: true,
			Family: "Berlin Sans FB Demi",
			Size:   36,
			Color:  "#777777",
		},
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	f.SetCellStyle(changeSheetName, "B3", "B3", style)

	// セルの高さ、幅を設定
	f.SetColWidth(changeSheetName, "B", "C", 20)
	f.SetRowHeight(changeSheetName, 3, 100)

	// 画像
	if err := f.AddPicture(changeSheetName, "D1", "image.png", ""); err != nil {
		fmt.Println(err)
		return
	}

	// 元の画像をスケーリングして出力
	if err := f.AddPicture(changeSheetName, "D5", "image.png", `{"x_scale": 0.5, "y_scale": 0.5}`); err != nil {
		fmt.Println(err)
		return
	}

	// 画像バイナリデータ版
	image, err := os.Open("image.png")
	defer image.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	img, err := png.Decode(image)
	if err != nil {
		fmt.Println(err)
		return
	}

	buffer := new(bytes.Buffer)
	if err := png.Encode(buffer, img); err != nil {
		fmt.Println(err)
		return
	}

	if err := f.AddPictureFromBytes(changeSheetName, "D10", `{"x_scale": 0.2, "y_scale": 0.2}`, "image", ".png", buffer.Bytes()); err != nil {
		fmt.Println(err)
		return
	}

	// [x, y]座標から英数字のセル名に変換する
	// [1, 1] => "A1"
	cellName, err := excelize.CoordinatesToCellName(1, 1)
	if err != nil {
		fmt.Println(err)
		return

	}
	fmt.Println(cellName)

	// セル内の改行
	f.SetCellValue(changeSheetName, "A12", "あいうえお\nかきくけこ")
	f.SetRowHeight(changeSheetName, 12, 60)

	if err := f.SaveAs("サンプル.xlsx"); err != nil {
		fmt.Println(err)
		return
	}
}
  • 出力結果

基本的には直感的に関数を使って操作が出来ると思います!
実際にExcelizeを使って実運用までに時間は掛からなかったくらい簡単です。

Tips: ファイルを開いたときに自動で再計算させる方法

最後にExcelizeを利用する上で困ったことの共有です!

既存ファイルを元にアプリケーション側で記録したデータを出力した後、別ファイルとして出力してファイルを開いたとき、セルの関数がうまく実行出来ないケースがありました。

その場合はExcelize側でFullCalcOnLoadプロパティを設定することで対応出来ました。

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"

	"github.com/360EntSecGroup-Skylar/excelize"
)

func main() {
	b, err := ioutil.ReadFile("ExcelizeSample.xlsx")
	if err != nil {
		fmt.Println(err)
		return
	}
	f, err := excelize.OpenReader(bytes.NewReader(b))
	if err != nil {
		fmt.Println(err)
		return
	}

	// アプリケーションで記録したデータを出力...

	// 開いたときに自動計算する
	if f.WorkBook != nil && f.WorkBook.CalcPr != nil {
		f.WorkBook.CalcPr.FullCalcOnLoad = true
	}

	if err := f.SaveAs("サンプル.xlsx"); err != nil {
		fmt.Println(err)
		return
	}
}

おわりに

いかがだったでしょうか。「Excelize」を使うことでExcelを簡単に操作出来ましたね!
非常に便利なパッケージだと思いますので、Excelを利用する場合はぜひ候補の1つに加えてみるのも良いと思います!

Discussion

ログインするとコメントできます