Karakuri.com

Fintechではたらくアプリケーションエンジニアの技術録

Image.FromFileはファイルをロックしてIOExceptionを発生させる原因になるので使うのをやめましょう

ユーザーに画像を選択してもらうアプリケーションを作成する場合、画像ファイルをローカルに保存することになると思います。このプレビュー画像をアプリケーションに表示しようとしたときに、このローカル画像を読み込まなければなりません。このときにImageクラスのFromFileメソッドを使用すると一見簡単なのですが、ファイルをロックしてしまうため気を付けてください。

IOExceptionが発生します

例えば下記のようなコードが存在すると危険です。

var image = Image.FromFile(fileName);

これが実行されるとfileNameのファイルがロックされたままとなります。再び上記コードが呼ばれるとIOExceptionが発生してしまいます。MSDNにも「The file remains locked until the Image is disposed.」と記述されています。

Disposeすれば解決なのか?

では、下記のように書けば問題は解決されるのでしょうか。

using(var image = Image.FromFile(fileName))
{
  ...
}

しかし開いたファイルはusingを抜けた後もアプリケーションにはプレビュー表示され続けているわけです。仮に下記のようになっていたらどのような挙動になるのでしょうか?

public Bitmap Image { get; private set; }

...

using(var image = Image.FromFile(fileName))
{
  Image = (Bitmap)image;
}

気持ち悪いですね。

Image.FromFileを使うのをやめる

このため、Image.FromFileを使うのはやめましょう。ImageクラスのFileStreamメソッドとFromStreamメソッドの組み合わせでファイルのロックを回避します。

using(var stream = Image.FileStream(fileName, FileMode.Open, FileAccess.Read)){
  using(var image = Image.FromStream(stream)){
     ...
  }
}

FileStreamメソッドはFileAccessが指定できるのでロックを回避することができます。画像を表示するだけならFileAccess.Readだけで十分です。どうしてFromFileメソッドは無条件で書き込み権限まで持たせるんですかねえ…。