【C++】Excelファイルを作成する


更新

 Windows環境にて、C++からlibxlsxwriterを呼び出してExcelファイル(*.xlsx)を作成する方法を説明します。

開発環境Visual Studio 2022
言語C++
ライブラリlibxlsxwriter 1.1.5
zlib 1.3
動作確認Windows 11
Windows 10
Windows 7

準備

 「libxlsxwriter」(https://github.com/jmcnamara/libxlsxwriter)は、Excelファイルを作成するための、WindowsやUNIX系OS等の複数のプラットフォームに対応するライブラリです。開発環境にも実行環境にもExcelは不要です。ただし、読み込み機能は、ありません。以下、libxlsxwriterをVisual Studio 2022にてビルドする手順です。

(1)
 最初に、zlibを作成します。何故、zlibが必要かというと、Excelファイル(*.xlsx)の正体はzipファイルだからです。https://zlib.net/からソース(zlib13.zip)をダウンロードして、展開します。

(2)
 ターミナルより、[Developer Command Prompt for VS 2022]を起動します(または、[スタート]-[すべてのアプリ]-[Visual Studio 2022]-[Developer Command Prompt for VS 2022])。仮に、ソースの展開先を「C:\temp\zlib13\zlib-1.3」、生成されるライブラリの出力先を「C:\temp\zlib13\zlib」とする場合、以下のコマンドを実行します。その際、-Aオプションは、組み込み先のソリューションプラットフォームに合わせます。x86の場合、「Win32」を指定します。


> cd C:\temp\zlib13\zlib-1.3
> mkdir build
> cd build
> cmake .. -G "Visual Studio 17 2022" -A x64 -D CMAKE_INSTALL_PREFIX:PATH="C:\temp\zlib13\zlib"
> cmake --build . --config Release --target install

(3)
 次に、libxlsxwriterを作成します。https://github.com/jmcnamara/libxlsxwriterのReleasesからソース(libxlsxwriter-RELEASE_1.1.5.zip)をダウンロードして、展開します。

(4)
 仮に、ソースの展開先を「C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter-RELEASE_1.1.5」、生成されるライブラリの出力先を「C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter」とする場合、以下のコマンドを実行します。その際、-Aオプションは、組み込み先のソリューションプラットフォームに合わせます。x86の場合、「Win32」を指定します。


> cd C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter-RELEASE_1.1.5
> mkdir build
> cd build
> cmake .. -G "Visual Studio 17 2022" -A x64 -D CMAKE_INSTALL_PREFIX:PATH="C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter" -D ZLIB_ROOT:STRING="C:\temp\zlib13\zlib"
> cmake --build . --config Release --target install

※「Could NOT find ZLIB (missing: 1.0) (found version "1.3")」エラーが発生する場合、~\libxlsxwriter-RELEASE_1.1.5\CMakeLists.txtの222行目を以下の通りに修正して、cmakeを再実行してください。


# 修正前
find_package(ZLIB REQUIRED "1.0")

# 修正後
find_package(ZLIB "1.0" REQUIRED)

(5)
 出力先より、必要なファイルは以下の通りです。任意の場所に移動することが可能です。

ファイル名備考
~\libxlsxwriter\includeフォルダー配下のファイル全部
~\libxlsxwriter\lib\xlsxwriter.lib
~\zlib\lib\zlibstatic.libzlibをスタティックリンクする場合、ビルド時に必要
~\zlib\lib\zlib.libzlibをダイナミックリンクする場合、ビルド時に必要
~\zlib\bin\zlib.dllzlibをダイナミックリンクする場合、実行時に必要。
アプリケーションと同じ、または、パスが通ったフォルダーに配置

(6)
 プロジェクトのプロパティに以下の設定を追加します。仮の出力先をそのまま使用する例です。任意の場所に移動した場合は、そちらに合わせてください。

[C/C++]-[全般]-[追加のインクルードディレクトリ]
C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter\include;
[リンカー]-[全般]-[追加のライブラリディレクトリ]
C:\temp\libxlsxwriter-RELEASE_1.1.5\libxlsxwriter\lib;C:\temp\zlib13\zlib\lib;
[リンカー]-[入力]-[追加の依存ファイル]
(スタティックリンク)
xlsxwriter.lib;zlibstatic.lib;

(ダイナミックリンク)
xlsxwriter.lib;zlib.lib;

サンプルソース

 libxlsxwriterのライブラリ関数は、C言語にて実装されています。ライブラリ側にてextern "C"しているので、そのままC++から呼び出しが可能です。

 また、引数に渡すパスやテキストの文字コードはUTF-8です。UTF-16からUTF-8に変換する方法は、「【C++/Win32】UTF-16とUTF-8を相互に変換する」を参照してください。


#include <xlsxwriter.h>


    // Excelファイルの新規作成
    lxw_workbook *workbook = workbook_new("test.xlsx");

    // シートの追加
    lxw_worksheet *worksheet = workbook_add_worksheet(workbook, nullptr);

    // テキストの入力
    // 2番目の引数は行のインデックス、3番目の引数は列のインデックス
    // いずれもゼロ開始(ゼロゼロがA1)
    worksheet_write_string(worksheet, 0, 0, u8"表示するテキスト", nullptr);

    // 数値の入力
    worksheet_write_number(worksheet, 1, 0, 123.45, nullptr);
    worksheet_write_number(worksheet, 2, 0, 654.32, nullptr);

    // 式の入力
    worksheet_write_formula(worksheet, 3, 0, "=SUM(A2:A3)", nullptr);

    // 終了
    workbook_close(workbook);

Excelファイルの作成例

 上記の例ならCSVファイルを作成したほうが早いですが、libxlsxwriterは、CSVでは不可能なExcelの機能も実装されています。公式ドキュメント(https://libxlsxwriter.github.io/)にて、チュートリアル、リファレンス、サンプルソース等、詳しく説明されています。

シートを追加する

 同じブックに対して、シート毎にworkbook_add_worksheet関数を実行します。


    lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, nullptr);
    lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, nullptr);
    lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, nullptr);

    // 2番目の引数はシート名
    lxw_worksheet *worksheet4 = workbook_add_worksheet(workbook, u8"2023年");
    lxw_worksheet *worksheet5 = workbook_add_worksheet(workbook, u8"2024年");
    lxw_worksheet *worksheet6 = workbook_add_worksheet(workbook, u8"2025年");

シートを追加する例

フォント等を設定する

 フォーマットを構成後、各セルに対して設定します。


    lxw_format *format = workbook_add_format(workbook);
    // メイリオ、サイズ10の例
    format_set_font_name(format, u8"メイリオ");
    format_set_font_size(format, 10);

    worksheet_write_string(worksheet, 0, 0, u8"表示するテキスト", format);
    worksheet_write_number(worksheet, 1, 0, 123.45, format);
    worksheet_write_number(worksheet, 2, 0, 654.32, format);
    worksheet_write_formula(worksheet, 3, 0, "=SUM(A2:A3)", format);

    // セルは、以下のような指定も可
    worksheet_write_string(worksheet, CELL("A1"), u8"表示するテキスト", format);
    worksheet_write_number(worksheet, CELL("A2"), 123.45, format);
    worksheet_write_number(worksheet, CELL("A3"), 654.32, format);
    worksheet_write_formula(worksheet, CELL("A4"), "=SUM(A2:A3)", format);

フォントを設定する例

 ここで、合計のセルのみ背景を黄色にしたい場合、新しく別のフォーマットを構成します。


    lxw_format *format_total = workbook_add_format(workbook);
    format_set_font_name(format_total, u8"メイリオ");
    format_set_font_size(format_total, 10);
    format_set_bg_color(format_total, LXW_COLOR_YELLOW);

    worksheet_write_formula(worksheet, 3, 0, "=SUM(A2:A3)", format_total);

セルに背景色を設定する例

フォーマット系のリファレンス

 https://libxlsxwriter.github.io/working_with_formats.html

列幅を設定する

 列幅に合わせて自動的にテキストを縮小するには、format_set_shrink関数を使用します。逆に、テキストに合わせて自動的に列幅を拡大する関数は、ありません。

[列の幅]数値指定

 Excelの[列の幅]にて表示される数値(デフォルトは約8)を、worksheet_set_column関数に指定します。実際には、指定した数値と約0.1ずれた幅が設定されます。使用するフォントによるのかもしれません。


    // 列A~Cに幅20を指定する例
    // worksheet_set_column(シート, 開始列, 終了列, 幅, フォーマット)
    worksheet_set_column(worksheet, 0, 2, 20, nullptr);

    // 列は、以下のような指定も可
    worksheet_set_column(worksheet, COLS("A:C"), 20, nullptr);

列幅を拡大する例

ピクセル指定

 実行環境の画面の「拡大/縮小」が100%の場合、worksheet_set_column_pixels関数にピクセルを直接指定できます。「拡大/縮小」の設定は、Windows 11/10は[設定]-[システム]-[ディスプレイ]-[拡大縮小とレイアウト]、Windows 7は[コントロール パネル]-[デスクトップのカスタマイズ]-[ディスプレイ]です。


    // 列A~Cに幅200ピクセルを指定する例
    // worksheet_set_column_pixels(シート, 開始列, 終了列, 幅をピクセルで指定, フォーマット)
    worksheet_set_column_pixels(worksheet, 0, 2, 200, nullptr);

 100%以外の場合、設定を取得して補正する必要があります。以下のソースは、実行環境が何%かに関係なく、テキストに合わせた列幅を設定します。


#include <windows.h>
#include <xlsxwriter.h>
#include <string>


    // Windows 11/10
    SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
    // Windows 7
    //SetProcessDPIAware();

    HDC hdc = GetDC(nullptr);

    // テキスト表示に必要なピクセルを取得するためのフォント指定
    // メイリオ、サイズ14の例。72は固定値
    LOGFONT lf{};
    std::wstring fontname = L"メイリオ";
    int fontsize = 14;
    wcsncpy_s(lf.lfFaceName, fontname.c_str(), fontname.size());
    lf.lfHeight = -MulDiv(fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
    HFONT hf = CreateFontIndirect(&lf);
    HFONT hfOld = (HFONT)SelectObject(hdc, hf);

    // ピクセルを取得
    // テキストは「テキストの幅に合わせる」の例
    SIZE size;
    std::wstring str = L"テキストの幅に合わせる";
    GetTextExtentPoint32(hdc, str.c_str(), static_cast<int>(str.size()), &size);

    // 画面のDPIを取得
    int dpi = GetDeviceCaps(hdc, LOGPIXELSX);

    // 解放
    SelectObject(hdc, hfOld);
    DeleteObject(hf);
    ReleaseDC(nullptr, hdc);

    // ここまで、Win32 APIの処理。取得した値は、size.cxとdpi
    // ここから、libxlsxwriterの処理

    lxw_workbook *workbook = workbook_new("test.xlsx");
    lxw_worksheet *worksheet = workbook_add_worksheet(workbook, nullptr);

    // 列Aに、「テキストの幅に合わせる」を表示できる幅を指定する例。96は固定値
    worksheet_set_column_pixels(worksheet, 0, 0, MulDiv(size.cx, 96, dpi), nullptr);

    // セルA1に、メイリオ、サイズ14にて表示する例
    lxw_format *format = workbook_add_format(workbook);
    format_set_font_name(format, u8"メイリオ");
    format_set_font_size(format, fontsize);
    worksheet_write_string(worksheet, 0, 0, u8"テキストの幅に合わせる", format);

    workbook_close(workbook);

テキストの幅に合わせる例

 ここで、GetDeviceCaps(hdc, LOGPIXELSX)が返す値は、「拡大/縮小」が100%なら96、125%なら120、150%なら144、200%なら192です。実際のモニターのDPIとは関係ありません。

 また、引数の文字コードは、Win32 APIはUTF-16、libxlsxwriterはUTF-8であることに注意してください。