概要
以下、自分用メモも兼ねています。
以前にExcel関連の処理をGoからいろいろ操作したりした記事を何個かアップしていました。
このときは自前のライブラリを使って、ごにょごにょしてたのですが、GoのExcelライブラリで有名な
とか
の方が使いやすいし楽だしで、最近ずっとそっち使っていました。
シートコピーする関数がない
んで、ひょんなことで、特定のフォルダの下にいっぱいあるExcelファイルの各シートを一つのExcelに纏めたいということがありました。
(章毎にフォルダが作られてて、その中に項番毎のフォルダがさらにあって、その中にExcelがあって、シートになんか画像とか結果とかが入ってると想像してください・・・)
おけ、んじゃ作るかってなって xlsx と excelize を使おうとおもったら、これらにシートをコピーする関数ってないんですね・・・。
excelizeの方には以下のようなissueがあって、まだopen状態でした。
xlsxの方もなんか情報ないかなーって探しみたら以下を発見。
見てみると、元のシートから各セルのデータ全部取得して持っておいて、コピー先のシートに全部書き込んでいくっていうサンプルでした。
これ、データがテキストとかだけだったらいいですが、画像とか表とかだったらちょっと厳しいですね。スタイルとかもなくなっちゃうし。。。
GoはやめてPythonでスクリプト書いちゃおう
んじゃ、pythonで作ろうって思って openpyxl のドキュメントみてたら copy_worksheet って関数あって、よく見ると以下の文言が。。。
This function cannot copy worksheets between workbooks. worksheets can only be copied within the workbook that they belong
別ファイルにあるシートをコピーするのは出来ないみたい。。残念。
VBAだったら、ワークシートにCopyって関数があるので、楽勝なんですけどね。。。やっぱりGoとかでやってみたいじゃんw
自前ライブラリにシートコピー関数を追加する
無いんだったら、自前のライブラリの方に追加しようってことにしました。
私のライブラリは go-ole を使ってExcel触っているので、VBAで出来ることはほぼ出来るはず。
てことで、以下の関数を追加。
func (ws *Worksheet) CopySheet(dest *Worksheet, after bool) error
中は、go-ole 経由でCopy関数呼び出しているだけですが。go-ole 素晴らしい。
サンプル
以下、サンプルです。スクリプトみたいな感覚で一度動けばいいのでエラー処理とかはほぼ無視しています。
package main import ( "flag" "log" "os" "path/filepath" "strings" "github.com/devlights/goxcel" ) // flag parameters var ( srcDir string out string ) // logs var ( wsLog = log.New(os.Stdout, ">>> ", 0) ) func main() { os.Exit(run()) } func run() int { flag.StringVar(&srcDir, "srcdir", "", "source directory") flag.StringVar(&out, "out", "result.xlsx", "output file name") flag.Parse() if srcDir == "" { flag.Usage() return 1 } quitFn, _ := goxcel.InitGoxcel() defer quitFn() g, r, _ := goxcel.NewGoxcel() defer r() _ = g.SetDisplayAlerts(false) _ = g.SetVisible(false) wbs, _ := g.Workbooks() wbDest, wbDestR, _ := wbs.Add() defer wbDestR() wsDest, _ := wbDest.Sheets(1) _ = filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } absPath, _ := filepath.Abs(path) if !strings.HasSuffix(absPath, "xlsx") { return nil } wsLog.Println(path) wb, wbr, _ := wbs.Open(absPath) defer wbr() wss, _ := wb.WorkSheets() _, err = wss.Walk(func(ws *goxcel.Worksheet, index int) error { err := ws.CopySheet(wsDest, false) if err != nil { return err } return nil }) return err }) wd, _ := os.Getwd() curdir, _ := filepath.Abs(wd) resultPath := filepath.Join(curdir, out) err := wbDest.SaveAs(resultPath) if err != nil { log.Println(err) return 2 } return 0 }
実行すると、-srcdir
で指定したディレクトリ配下の全Excelファイルを開けて、その中のシートを全部コピーして一つのExcelファイルに集約します。
とりあえず、自分の望みの結果は手に入ったのでスッキリ。
おすすめ書籍
自分が読んだGo関連の本で、いい本って感じたものです。

- 作者:Katherine Cox-Buday
- 発売日: 2018/10/26
- メディア: 単行本(ソフトカバー)

- 作者:松尾 愛賀
- 発売日: 2016/04/15
- メディア: 単行本(ソフトカバー)

プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- 作者:Alan A.A. Donovan,Brian W. Kernighan
- 発売日: 2016/06/20
- メディア: 単行本(ソフトカバー)
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場