2025-12-29

openpyxl で 保存が重い、出来上がったファイルが大きすぎると感じたとき

実際の失敗談からの展開になります

openpyxl で作ったエクセルファイルがやけに大きい


あれれ、何かおかしいぞ?
前々から ii-win-merge は少し重たくて、ii-diff は軽い!!

そんな印象を持っていたんですが
100 を超えるファイルを比較したときに、顕著にその差が見て取れて

ついに「おかしい!」と確信する事態となりました!!


重たい!という症状は

PC 全体の動きがもっさりしだすし
タスクマネージャを見ると メモリはフルに・・・

HDD も 14GB くらいの余裕があったのに
数百MB まで落ちている

そして、最終的にエラーで結果の出力ができない!ときた・・・



絶対、どこかでメモリリークのような開放漏れがあるんだろうと思いました

そこからは いろいろと トライ&エラー です orz
1回のトライ(ここを変えたらどうなる?ってお試し)に 3~5H かかりました

なんせ
100 を超えるファイルを比較して、処理が終わるころにエラーするもんだから


いちいち時間がかかる
そして、その間、PC が重くなるから、何もできなくなります

難航しました・・・


原因がわかったのは
ファイル数を 50個くらいに抑えて出力した結果を ii-diff の結果と比較しているときでした


差分表の最後の行から Ctrl+下 でジャンプするファイルの最終行の位置が違う!!


そこに気づき着目しました!

ii-diff は 1,048,576行 (← 最新のエクセルで扱える最大行数)
ii-win-merge は 65,535行





行数が少ない ii-win-merge の方がファイルが大きくなるのはなぜ?と思う人もいるかもしれないですが・・・



ii-diff は値の入っている有効行が 差分表の最後の行(116行目)なのでエクセルの最終行に飛び
ii-win-merge は エクセルの最終行に飛ばないので、
差分表の後にも値の入っている行があって、その値の入っている最後の有効行に飛んだのだろう

そう解釈をしました (;^ω^)

よく見ると



実際
上図のようにグレー塗のセルが 65,535行まで続いていました


絶対これやん!!


そこを修正したら、さっくり軽くなり、約 7分 で結果出力できるようになりました ('ω')ノシ



シート当たりのデータ量が無駄に多かったんだもん
そら重いわな・・・


結論

openpyxl は ワークブックの save() で時間がかかります
保持していたデータを xml にして、エクセルのファイル構成を作って
zip に圧縮するらしいです

データ量に比例して時間が増えますので、
小さなデータを扱っているつもりなのに、とても時間がかかるときは

私のように
意図せず広い範囲のセルを使っていないか、ご確認くださいませ 🙇‍♂️🙇‍♂️🙇‍♂️







2025-12-26

相対パス指定のショートカットを作成する方法

 Windows でショートカットを作成すると絶対パスで本体を示すショートカットが作成されます ('ω')

 

会社生活を長くやっていると

 ・サーバーが変わりました

 ・旧サーバーから新サーバーでファイル・フォルダ構成そのままでコピーされる

ってことがときどき起こりえます


このとき、サーバーに置かれていたショートカットがリンク切れを起こして困ってしまいます

あらかじめ、絶対パスではない、相対パスのショートカットを配置しておけば、困ることもないのかな?と

 

相対パスでショートカットを作成できないかを調べてみた 口笛

 

ChatGPT 調べですが、Windows は標準では相対パスを推奨していないみたいで裏技的な技法らしいのですが、

リンクのプロパティからリンク先を以下のように指定したらよいらしいです ('ω')ノシ


%windir%\explorer.exe ..\ii-create-shortcut\icon.ico

 

実際、これをやろうとすると・・・ 以下のように、まぁまぁの手数が必要で かつ 相対パスを作り上げるのが面倒です

 

 1. ショートカットを作成する(本体ファイルを右クリック → ショートカットの作成) ※Win11 なら右クリックの後もう1手が必要

 2. ショートカットを適切なフォルダに移動させる

 3. 相対パスの文字列を作成する

 4. ショートカットのリンク先を変更する(ショートカットを右クリック → プロパティ → リンク先欄の修正)


ということで、

相対パス指定のショートカットを作成するアプリを作ってみました!! ('ω')ノシ


こちら になります

どうぞお試しくださいませ



2025-12-18

python openpyxl は自動計算ができない! (TдT)

openpyxl でセルに値を入れ、

他のセルには、openpyxl で入れるセルを参照して計算した結果が入るようにして、

さらにそのセルの計算結果を openpyxl で読み込んで処理するようにしていた (´・ω・`)


何度見ても何度試しても期待通りに動かない!!

 

 

よくよく調べてみると

エクセルの計算式は評価され、計算結果が保存されるタイミングがあるみたいで

 

openpyxl は保存されている計算結果を参照するから

openpyxl で入れた値を使って再計算されないことがわかった

 

くそぅ (´;ω;`)

 

 

何か方法はないかなと…

 

調べてみると xlwings, pyxlsb, win32com ではできそうな情報がありました (・・;)

 

まず、xlwings を試すも再計算されたり、されなかったり、

何がなんやらわからんちーな状態で1時間を浪費 (TдT)

 

どうしたらいいやら・・・



次に xlwings で解決できないかな、と試してみました (・∀・)ノシ

 

 

結論は 「できました!!」 ですが、小手先の対応感があります (・・;)

 

コードは以下、これを再計算させたいタイミングで実行しました (;´・ω・)

with xw.App(visible=False) as app:
    wb = app.books.open(path)
    wb.app.calculate()

    ws = wb.sheets[toolname]
    val = ws.range(1, 1).value
    ws.range(1, 1).value = " "
    ws.range(1, 1).value = val

    wb.save()
    wb.close()

 

見る人が見たらすぐわかると思いますが・・・

 

xlwings でエクセルをひらいて、計算をするための API をぶったたいた後、

A1 セルの値を一時退避、" " を書き込んだ後、元に戻して、保存・終了するっていう謎処理をしています (;^ω^)

 

ChatGPT さんも Copilot さんも上記の wb.app.calcutate() とか、なんやらほかにも紹介してくれたけど

動いたり・・・ 動かなかったり・・・ 試すたびに何か動きが違う・・・

 

バタついていました

 

 

結局、前述のような処理にすることで確実に再計算が行われるようになりました ('ω')v

 

 

強引だな・・・ と思いますが、Windows ってそういうところあるよね・・・ ということにして、

この件はこれで終了としようかな、と思っています ('ω')ノ

 

 

「これが本当に正しい対応の仕方だ!!」 をご存知の方、いらっしゃいましたら、ぜひご教授くださいませ m(_ _)m

python で Windows アプリを作ろう!! exe化する方法 ('ω')ノシ

python プログラムの exe化 の方法を記しておきます 真顔

実はノウハウの必要とするところなんじゃないかな、と感じたため残すこととしました 

 

ややこしい話もあるけど、「まずは試してみたらできました!!」の体験を大事にしたいので、

ややこしい話は抜きに手順だけ示したく、以下の順で述べます

 

 1 とにかく exe化

 2 仮想環境を使って軽量化(というより重量化の抑止)

 3 アイコンの封入

 

1 とにかく exe化

細かいことはさておき、さっさと exe化 を試したいなら以下の手順で exe ができあがります

pip install pyinstaller

pyinstaller --onefile sample.py

--noconsole はお好みで付けたらよいかな

 

上記の実行で、dist フォルダができて、そこに sample.exe ができあがっています

ご確認くださいませ ニヤニヤニヤニヤニヤニヤ


2 仮想環境を使って軽量化(というより重量化の抑止)

python 開発環境には 過去に pip install したライブラリもすべて入っています ('ω')

そこには exe化したいアプリで使うライブラリ以外も当然ながら存在するので、

 

そこで exe化 すると不要なライブラリも含まれ、とっても大きな exe ができあがっちゃいます ( ゚Д゚)ノシ

 

私の環境だと、100MB を超えるものが作られます!! (;^ω^)

 

なので、仮想環境を作って、そこで必要なライブラリを pip install して exe化します ('ω')ノ

 

python -m venv venv

venv\Scripts\Activate

pip install pyinstaller

pip install ***     ※ *** は適宜必要なものをご指定くださいませ

python -m PyInstaller --onefile sample.py

 

仮想環境を終わるときは以下のコマンドをたたいておきましょう (・ω・)

うっかり忘れると、別アプリ用のライブラリをインストールするなど、悲しい事故がおきます (;^ω^)

venv\Scripts\Deactivate

 

3 アイコンの封入

作ったアプリには独自のアイコンを表示させたいですよね (/o\)

 

exe化する際のコマンド引数に --icon=icon.ico を入れるとアイコンが入るけど・・・

Window を持つアプリの場合の Window の左上のアイコンは変化しないです

 

調べるのに苦労しました (;^ω^)

 

あわせて変更する方法を記します

 

アイコンを指定するところを下記のように変更をして、

icon_path = get_resource_path("icon.ico")
root.iconbitmap(icon_path)

 

上記で呼ばれる関数(以下)を配置する

def get_resource_path(relative_path):
    """PyInstaller でパッケージ化された実行ファイルからのパスを取得"""
    if getattr(sys, 'frozen', False):
        # PyInstaller でビルドされた場合
        base_path = sys._MEIPASS  # 一時ディレクトリに展開される
    else:
        # 通常のスクリプト実行時
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

 

exe化の際のコマンドは以下のように指定する

python -m PyInstaller --onefile --icon=icon.ico --add-data "icon.ico:." sample.py

 

以上でいい感じにアイコンが表示されると思います ('ω')ノ

 

python で バルーン通知をしてみる!

2つ方法があるみたい

 
plyer と win10toast
 
それぞれ pip install plyer / win10toast をしたうえで、以下のコードで動かしてみた
 
・plyer
from plyer import notification

notification.notify(
    title="バルーン通知したい ('ω')ノシ",
    message="「激おこぷんぷん丸」 の今は?",
    app_name="ii-test",
    timeout=10  # 表示時間(秒)
)
・win10toast
from win10toast import ToastNotifier

toaster = ToastNotifier()
toaster.show_toast("バルーン通知したい ('ω')ノシ", "「激おこぷんぷん丸」 の今は?", duration=10)

微妙に違う結果、上が plyer 、下が win32toast ・・・ 
 

どっちがいいんだろう? 
 
動作確認はできていませんが、軽く調べた情報を以下にまとめてみます
 
特徴plyerwin10toast
OSマルチ(Win/Mac/Linux)Windows10以降
カスタムアイコン、タイトル、メッセージ、表示時間タイトル、メッセージ、表示時間
アイコンOS による(Win は 可)指定不可
バックグラウンド実行OS による(Win は 可)
 
う~ん
これだけ見ると plyer 一択だな
アイコン変えられないってどういうことだろう (;^ω^)
あたしゃ、まず、変えたくなるんだけどなぁ・・・

2025-12-07

msys2 で python の開発環境を整える

 AIエンジニアになれと? そういう話で python を使わなければならないことになった (;'∀') マジスカ

 

今まで anaconda でちょこっとお遊び程度に環境を作って動かしたことはあるんだけど、

あらためて、「本気出して頑張れ!」 ほどではないけど、環境を作って事前課題とやらをやらなければならない

 

数学の勉強を8時間、python の勉強を8時間せよと・・・(YouTube 動画にて・・・)

そして、そのあとに事前課題を2時間やれと・・・ (; ・`д・´)

 

むーーーーーーーーーーーーーーーー (・´з`・)

 

ひとまず、お試しで家のパソコンで試してみる

以下に、その記録をしていく ('ω')ノシ

 

1. msys2 をインストール

 http://msys2.org


2. 連打!!

 Windows キー -> msys2

 # pacman -Syuu    ' msys2のパッケージマネージャー? を最新状態へ

 # pacman -S base-devel

 # pacman -S msys2-devel

 # pacman -S vim

 # pacman -S git

 # pacman -S openssh

 # pacman -S mingw-w64-x86_64-python

 

3. パス設定

 以下の順番になるように設定しないといけないらしい

  c:\msys64\mingw64\bin

  c:\Users\<UserAccountName>\AppData\Local\Microsoft\WindowsApps

 ※操作方法:(Win11)設定 -> システム -> バージョン情報 -> システムの詳細設定 -> 環境変数

 

4. 環境起動&お試し

 Windows キー -> mingw  or  Windows キー -> msys2

 # python --version

 -bash: python: command not found  ' (゚д゚)! 動かないんですけどっ!?

 

5. cmd プロンプトでは?

 Windows キー -> cmd

 # python --version ' 動いた


6. リトライ

 Windows キー -> mingw  or  Windows キー -> msys2

 # export PATH=$PATH:/c/msys64/mingw64/bin

 # python --version ' 動いた

 # vim ~/.bashrc ' 以下の記述を最後尾に追加

  alias vi=vim

  export PATH=$PATH:/c/msys64/mingw64/bin:/c/Users/<UserName>/AppData/Local/Programs/Python/Python312/Script/

 

ってことで、ひとまず、vi と python が動いたのでよかった ( *´艸`) 

 

参考

 

 

 

 

wsl 上の ubuntu に Jenkins サーバーを設置する #001

 wsl に ubuntu を動かす方法は ここ で頑張りました


Jenkins & Java11環境 をインストールは こちら を参考に、root で以下の手順で実行したが・・・

 

apt -y install openjdk-11-jdk

 

# 公開鍵の取得

curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null

 

# Jenkins インストール時に使うもの(Jenkins のある外部リポジトリを参照するため)

echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]  https://pkg.jenkins.io/debian-stable binary/ | tee /etc/apt/sources.list.d/jenkins.list > /dev/null
 

# Jenkins を使うための公開鍵を取得する

wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -

 

# Jenkins の Debian の apt リポジトリをシステムの apt ソースリストに追加する

sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list' 

echo deb http://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list

 

# apt のアプデ(Jenkins のある外部リポジトリの情報を取得)

apt update


# Jenkins のインストール

apt install Jenkins

 

記事にあった 「E: Unable to locate package Jenkins」 エラーは改善されず、

ChatGPT にお伺いを立てて、Jenkins は apt ではなく dpkg でインストールをした (;^ω^) 

wget http://pkg.jenkins.io/debian-stable/binary/jenkins_2.387.3_all.deb

dpkg -i jenkins_2.387.3_all.deb

apt-get install -f

 

# Jenkins の起動

systemctl start jenkins

# Jenkins の常時起動設定

systemctl enable jenkins

 

### ホストPC の ブラウザから http://<wsl ubuntu IPアドレス>:8080

### 初回セットアップ画面が表示され、admin パスワードを求められる

 

# Jenkins admin パスワードは以下で確認する

cat /var/lib/jenkins/secrets/initialAdminPassword

 

ここまでで、Jenkins 自体のインストールができたので、次は Jenkins の初期設定を進めていきたい


Windows(WSL) で Ubuntu を動かす

ここ で Windows 上に python 環境を作るのに msys2 を使ってみたけど、

つまり、そこで msys2 で unix 環境ができたわけだけど、

 

やっぱネイティブな? 

純粋な unix 環境で、いろいろ試したいこともあるので、VM で unix 環境を作ることにした

 

やったことを記しておきます

 

1. WSL をインストールする

wsl --install

wsl --set-default-version 2

2. Microsoft Store から Ubuntu 24.04.1 LTS をインストールする

 ※ 24.04.1 LTS は 現時点(2024/11/03)最新と思われるので指定した

  WSL のネットワークは 標準で NAT になっているらしい

 ※これだけで ubuntu が動くと思っていたけど、うごかなくて、手順3, 4, 5 をした

3. HyperV を有効にする

dism.exe /online /enable-feature /featurename:Microsoft-Hyper-V -All /norestart

 4. WSL を有効化する

dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /norestart
dism.exe /online /enable-feature /featurename:WindowsSubsystemForLinux /norestart ※エラーした

5. 再起動する

6. メニューから ubuntu を起動する

7. 初期設定&ssh サーバー起動する

apt update

apt upgrade

 

apt install -y openssh-server

 

# ssh サーバー起動

service ssh start

# ssh サーバーの自動起動設定

systemctl enable ssh

# ssh サーバーの起動状態の確認

service ssh status

 8. root パスワードの設定&ユーザー追加(&sudo 設定)する

passwd

 

useradd <ユーザー名>

passwd <ユーザー名>

 

usermod -aG sudo <ユーザー名>

9. マシン名を変える

 /etc/wsl.conf に以下の行を追加する

[network]
hostname = new-hostname

 ※ wsl 上の ubuntu の IP は起動するたびに変化するらしい

  仮想環境であることが原因なので、固定IP運用も難しいみたい

  調査していこう・・・

10. お好みで・・・

apt install net-tools

!!注意!!

 ・Windows の終了で、 ubuntu は自動で終了するらしい

  ただし、ubuntu 上のプロセスは終了させられるので、動作保証が・・・

  明確に手動で終了させる場合は PowerShell で以下のように打つようだ

wsl --shutdown

   ubuntu のシェルで exit しても終わるようだ

 ・Windows の起動で、 ubuntu は自動起動しない

  以下のようにタスクスケジューラを設定したらいいみたい(未試行なので、メモ・・・)

  • 「タスクスケジューラ」を開き、「基本タスクの作成」から新しいタスクを作成します。
  • 「トリガー」で「Windows にログオンしたとき」を選択。
  • 「操作」で wsl.exe を実行するよう設定します。

 ・Windows のファイルは /mnt/<ドライブ名> で見える♪ (・ω・)ノシ


以下、まだやっていないけど、そのうち、必要になるような気がするのでメモしておく (;^ω^)

 

Appendix.A ポートフォワード設定 ★まだ、うまく動かない・・・

A1. PowerShell にて以下のコマンドで設定ができる

netsh interface portproxy add v4tov4 listenport=<Windowsのポート番号> listenaddress=0.0.0.0 connectport=<WSLのポート番号> connectaddress=127.0.0.1

A2. 設定の確認

netsh interface portproxy show v4tov4

A3. 補足:設定を削除する場合

netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=<ホスト側のポート番号>

A4. ファイアーウォールの設定

New-NetFirewallRule -DisplayName "WSL Web Server Port" -Direction Inbound -Protocol TCP -LocalPort 8081 -Action Allow



openpyxl で 列幅 の設定でトラブった内容の覚書

エクセル差分抽出ツール(ii-excel-diff)で、オリジナルのエクセルと同じセル幅で出力エクセルを設定しようとしても、うまくいっていないファイルがありました

openpyxl あるいは エクセル のクセのようなものと思われるため、その内容について記録しておくこととします

列幅がオリジナルと異なってしまう現象

列幅をオリジナルと同じ値で設定して、見た目を同じにしたいので、以下のようなコードを書いていました

target_ws.column_dimensions[get_column_letter(col + col_num)].width = source_ws.column_dimensions[get_column_letter(col_num)].width

これでほとんどのエクセルで問題なく動作していましたが、一部のエクセルファイルのときだけ、
下図のように オリジナル とは列幅が異なる結果となっていました

画像
列幅が異なっている図

原因の推測

1.コーディングミス:右辺の変数の参照先の間違い

代入するもの自体が間違っていたら、そらもうおかしいよね・・・
配列を使っているので、要素番号が間違っているのではないか?と確認するも問題なし

まぁ、当然ですよね・・・
一部のファイルだけ列幅がコピーされていないので・・・

実際に ***.width の値がどうなっているか?を見てみると意外な数値が並んでいました

2.0
13.0
13.0
13.0
 : 以下略

見た目上の列幅のサイズは全列で 2.1
1列目(上図の1行目)の値こそは近しい数値ではあるものの、他はすべて 13.0 で異なる数値となっています
いよいよ要素番号以外で何か参照先が異なるのか?と思い、コードを見直すも問題なし

2.設計ミス:右辺を参照する条件の間違い

オリジナルのエクセルは Ctrl+A で全セルを選択の上、列幅を変更していたため、1つ前の結果もあり、***.width を参照する前に、その値を参照すべきか否かの条件があるのだろうと推測をしました

結果、***.width = None のときは、列幅にシートのデフォルト値(source_ws.sheet_format.defaultColWidth)を使うという情報にいきつきました

しかし、13.0 が入っているんだよね・・・

ChatGPT や google 検索で調べるも、これといった情報もなく、openpyxl では、この課題は解決できないものと判断しました

3.課題まとめ

ライブラリ仕様とでもいいましょうか、普通には解決しないことがわかりました
結果、整理しますと下記の課題となります

  • Ctrl+A などで複数列を選択した状態で複数列の列幅を変えると
    ***.width の値は変更されず、シートデフォルト値の値が変更される

  • 結果、***.width に値は入っているが、***.width を信頼してはいけないケースが存在する

  • ***.width を信頼してよいか、わるいかを判断する情報は提供されていない

対策の検討

1.別のライブラリで列幅を調べる

ChatGPT によると win32com あるいは xlwings を使うことで、列幅を取得できるような解決策を示してくれました

openpyxl と似たようなコードにしか見えないが・・・

2.仮説:一番多い列幅値を使う列の信頼性が怪しいからその列の列幅はデフォルト値を入れたらいいのではないか

Ctrl+A で複数列を選択して、列幅を変更することによって ***.width には値が入らず、None でもなく、デフォルト値に値が入るということならば、
もしかして、ほとんどの列は 「同じ値が入っている」 のではないかと思いました

実際、13.0 が入っている訳ですから・・・

対策の実施・結果

対策は 検討2 の内容をベースに対策をすることとする

検討1は openpyxl と同じようなコードで同じようなことをしているだけなので、本当に改善するのか怪しいなと思ったことと、ライブラリを増やすことで処理速度や exe の肥大化が嫌だったので、試すことなく採用しないと判断しました

検討2はしきい値(どのくらい同じ値がでてきたら、デフォルト値を採用するか)を決めるのに難しさを感じますが、基本的には問題なく、試してみる価値があると感じ、

検討2の内容をベースに対策することとしました

細かくは書かないですが、一番発生頻度の高い列幅値で かつ 発生確率が xx 以上(企業秘密w)の場合に、デフォルト値を採用するようにしました

結果:オリジナルと同じ列幅で設定ができました

画像
改善前後の出力結果


ご訪問をありがとうございます ✨✨✨

八百茄子 は ソフトウェアエンジニア1名による小さな工房です 週末に スキルアップ と 八百茄子 向けのコンテンツ作成に勤しんでおります ご提供コンテンツ tools  にて 八百茄子 の作成したツールをご紹介しています knowhow  にて、 2x年の組込み系ソフトウェア開発...