Pythonで処理した結果を既存のExcelファイルに出力して保存したいことって結構ありますよね!!
手順はopenpyxlを利用して以下のようにしていることが多いと思います。
- load_workbookで既存のファイルを開く
- 出力内容を既存のファイルに書き込む
- 保存する
この時に、既存のファイルを開いた状態で実行してしまうと以下のエラーが出てしまいます。
PermissionError: [Errno 13] Permission denied: 'xxxx.xlsx'
これは、ファイルが開いている状態のため保存することができないという意味のエラーです。
このエラーは,PythonでExcelを扱ったことがある人は、ほぼ見たことがあると思います。
このエラーは、ファイルを閉じてからやり直せば問題ないのですが、出力前にチェックして、開かれていた場合はエラーメッセージを表示させるようにしたいと思い、チェックする関数を作ってみました。
Excelファイルが開かれていないかチェックする関数
以下がExcelファイルが開かれていないかチェックする関数です。
2023/3/28追記
dirsenseさんからわざわざopenpyxlで開かなくても、ファイルを追記モードで開くことで簡単にチェックができる方法をメッセージいただきましたので修正しました。
dirsenseありがとうございます。
#ファイルを追記モードで開けるかチェック
def xlsx_is_open(filepath: str) -> bool:
try:
f = open(filepath, 'a')
f.close()
except:
return True
else:
return False
if __name__ == '__main__':
if xlsx_is_open('test.xlsx'):
print('test.xlsxが既に開かれています')
ファイルの追記モードでファイルが開けるかチェック
Excelファイルが開かれているかをチェックするためにファイルの追記モードでファイルを開きます。
ファイルが既に開かれている場合は、例外が発生します。
例外処理を行う
例外が発生したときはリターンコードTrueを返し、それ以外の時はFalseを返します。これでファイルが既に開かれている場合は、関数xlsx_is_openのリターン値がTrueとなるので
以下のprint文が実行されます。
print('test.xlsxが既に開かれています')
また、ファイルが開かれていないときは、else:のブロックに正常終了したときの出力処理を書きます。
Pythonはelse:がかけるので便利ですね!!!
これでファイルが開いていない状態では処理を続行し、開かれていた場合はエラーメッセージを表示させるようにすることができました。
コメント
ファイルを追記モードで開けるかどうかチェックしてみるのも有力な選択肢かと思います。Excelファイルを指定しても同様に機能しました。この方法であればファイルが大容量であっても確認は一瞬で済むかと思います。
def file_is_open(filepath: str) -> bool:
try:
f = open(filepath, ‘a’)
f.close()
except:
return False
else:
return True
if __name__ == ‘__main__’:
if file_is_open(‘path/to/test.xlsx’):
print(‘既に開かれています’)
———————————————————————
それと載せていただいた下記のコードですと、
wb = px.load_workbook(filepath)
try:
wb.save(filepath)
openpyxlの関数でloadしてsaveしていますので、openpyxlの特徴として、(現時点では)保存時に図形を保持できないというのがあります。なので、図形を含んだExcelファイルをこの関数に掛けると図形の情報が失われてしまうかと思います。
(他にもVBAコードの情報もデフォルトでは保持できませんが、それに関しては px.load_workbook(filepath, keep_vba=True) のように引数を設定すれば問題回避できます)
以上、ご参考になれば幸いです。
私の書いた関数ではTrueとFalseが逆でした。
以下が正しいです(開かれていればTrue、そうでなければFalse)。
def file_is_open(filepath: str) -> bool:
try:
f = open(filepath, ‘a’)
f.close()
except:
return True
else:
return False
dirsense さん
コメントありがとうございます。
確かにわざわざload_workbookする必要はないですね!
こちらのほうが使い勝手が良いですね!
ありがとうございます。記事にもこの内容を追加させていただきたいと思います。