ぺぷしのーげん

アプリケーションエンジニアによる雑記ブログ

C#のImage.FromFileがファイルをロックする問題について|FromStreamとFileStreamを使え!

f:id:hazakurakeita:20150902220743j:plain

先日、フォルダ削除に関する不具合を修正していました。中身のファイル削除に失敗し、フォルダの削除も失敗してしまっていたもの。しかしこのプログラム、フォルダの削除に失敗したときの処理がない。つまり、途中で削除に失敗してもそのままだったのです。いやいや、途中まで削除したファイルを復旧してから削除失敗の通知しないとね。まあ、その削除失敗通知もしてなかったんですがね。

 

どういうときにフォルダ削除失敗するのか

今回修正していたプログラムの場合、フォルダ内の画像ファイルの削除に失敗する可能性があることが分かりました。2つのアプリケーションが同じ画像ファイルにアクセスしているのです。そして、お互いにアクセスするとIOExceptionがスローされることに気が付きました。これが発生すると、一方のアプリケーションが画像を表示できません。今回ここの修正もするハメになってしまいました。とほほ。

 

なぜIOExceptionが発生するのか

原因はこいつでした。

FromFileメソッドはファイルをロックするようです。MSDNにもはっきりと明記されています。

ファイルはまでロックされたまま、Imageが破棄されます。

https://msdn.microsoft.com/ja-jp/library/4sahykhd(v=vs.110).aspx

 なんだこの日本語。

英語は「The file remains locked until the Image is disposed.」です。Disposeされるまでファイルはロックされ続けるようですね。

 

一般的な解決策は?

 FromStreamを使うのが一般的な解決策のようです。

 しかしこいつはちょっと回りくどい。ちゃんとコメントで何故こういう処理にしてるのかを書いたほうが良いですね。別の部分に上記のような処理があったのですが、危うくシンプルに書き換えてしまうところでした笑。

 

usingでFromFileを囲む方法もあるらしい

実は今回の修正、原因だけ調べて修正はインド人に任せました。すると、FromStreamを使わずに修正してきたのです。うそーん。

 これじゃ問題解決しないだろーって動かしてみたら、問題が再現しない。うそーん。なんかDisposeされるんですかねー?それともGCの関係で再現しなかっただけとか。

stackoverflow.com

一応解決策の1つとして提示されてますね。でもやっぱしFromStreamのほうが安全っぽい。

 

ということで、複数からアクセスする可能性がある場合はFromStreamを使いましょう。そしてその理由もコメントしておいてください。僕みたいな人にデグレリファクタリングされますよー笑

 

おしまい。