🐡

C#でファイルがロック中であるかを確認する

2022/11/07に公開

はじめに

WindowsのC#でファイルがロック中であるかを確認する方法について記載します。

詳細

  • ファイルが存在しない場合はロック中とは判定しない。
  • 本メソッドの返却結果は「ファイルが存在し、他プロセスがロックしている」こととする。
  • 基本はFileStreamでFileMode.Open, FileAccess.ReadWriteで開いて例外が出るかを確認する。
  • FileMode.Openが必須で他のFileModeだとファイルに影響が出る場合がある。
  • 例外の種類は可能な限り区別する。
  • 例外が発生したという結果だけだとファイルが存在しない場合もロック扱いになるため
  • 具体的に他プロセスがロック中の場合にはIOExceptionが発生する。
  • IOExceptionで更に厳密に区別するのは言語リソース文字依存があるので困難であった。
  • ファイルの存在確認とFileStreamで開いてみるまでの間に削除される場合があるのでFileNotFoundExceptionも区別する。
  • DirectoryNotFoundExceptionも区別する。
  • またこれらの例外はIOExceptionを継承しているので順序に注意する。
  • 例外発生してから返却までの間にファイルが消える場合もあるので念のため再チェックする。

実装したコード

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp5
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public bool isFileExistsAndLocked(string path)
        {
            if (File.Exists(path))
            {
                FileStream stream = null;

                try
                {
                    stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                }
                catch (DirectoryNotFoundException e)
                {
                    return false;
                }
                catch (FileNotFoundException e)
                {
                    return false;
                }
                catch (IOException e)
                {
                    if (File.Exists(path))
                    {
                        return true;
                    }
                }
                catch (Exception e)
                {
                    return false;
                }
                finally
                {
                    if (stream != null)
                    {
                        stream.Close();
                    }
                }

                return false;
            }

            return false;
        }
        private void TEST1()
        {
            var ret = isFileExistsAndLocked(@"C:\tmp\test.txt");
        }
        private void button1_Click(object sender, EventArgs e)
        {
            TEST1();
        }
    }
}

まとめ

偏執的なチェックにも思えますが、これに落ち着きました。

その他

FileShare.NoneではNGでした。
FileShare.ReadWriteにしないと他のプロセスの挙動に影響が出ます。
一瞬であれ排他状態となるため音楽や動画再生などの場合エラーで停止する場合があります。

Discussion